Loading app/src/main/java/foundation/e/apps/domain/login/usecase/UserLoginUseCase.kt +4 −4 Original line number Diff line number Diff line Loading @@ -4,8 +4,8 @@ import app.lounge.model.AnonymousAuthDataRequestBody import app.lounge.model.AuthDataResponse import foundation.e.apps.domain.login.repository.LoginRepository import foundation.e.apps.utils.Resource import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.single import retrofit2.HttpException import java.io.IOException import java.util.Properties Loading @@ -15,10 +15,10 @@ class UserLoginUseCase @Inject constructor( private val loginRepository: LoginRepository, ) { operator fun invoke( suspend operator fun invoke( properties: Properties, userAgent: String ): Flow<Resource<AuthDataResponse>> = flow { ): Resource<AuthDataResponse> = flow { try { emit(Resource.Loading()) val userResponse: AuthDataResponse = loginRepository.anonymousUser( Loading @@ -33,5 +33,5 @@ class UserLoginUseCase @Inject constructor( } catch(e: IOException) { emit(Resource.Error("Couldn't reach server. Check your internet connection.")) } } }.single() } No newline at end of file app/src/main/java/foundation/e/apps/presentation/login/LoginViewModel.kt +18 −18 Original line number Diff line number Diff line Loading @@ -29,8 +29,6 @@ import foundation.e.apps.domain.login.usecase.UserLoginUseCase import foundation.e.apps.ui.parentFragment.LoadingViewModel import foundation.e.apps.utils.Resource import foundation.e.apps.utils.SystemInfoProvider import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import java.util.Properties import javax.inject.Inject Loading Loading @@ -151,10 +149,11 @@ class LoginViewModel @Inject constructor( properties: Properties, userAgent: String = SystemInfoProvider.getAppBuildInfo() ) { viewModelScope.launch { userLoginUseCase( properties = properties, userAgent = userAgent ).onEach { result -> ).also { result -> when (result) { is Resource.Success -> { _loginState.value = LoginState(isLoggedIn = true) Loading @@ -168,6 +167,7 @@ class LoginViewModel @Inject constructor( _loginState.value = LoginState(isLoading = true) } } }.launchIn(viewModelScope) } } } } app/src/test/java/foundation/e/apps/Shared.kt 0 → 100644 +15 −0 Original line number Diff line number Diff line package foundation.e.apps import app.lounge.model.AnonymousAuthDataRequestBody import com.aurora.gplayapi.data.models.AuthData import java.util.Properties val testAnonymousRequestBodyData = AnonymousAuthDataRequestBody( properties = Properties(), userAgent = "testUserAgent" ) val testAnonymousResponseData = AuthData("eOS@murena.io", "") const val loginFailureMessage = "Fail to login" No newline at end of file app/src/test/java/foundation/e/apps/presentation/login/LoginViewModelTest.kt 0 → 100644 +108 −0 Original line number Diff line number Diff line package foundation.e.apps.presentation.login import androidx.arch.core.executor.testing.InstantTaskExecutorRule import foundation.e.apps.testAnonymousRequestBodyData import foundation.e.apps.data.login.LoginSourceRepository import foundation.e.apps.domain.login.usecase.UserLoginUseCase import foundation.e.apps.loginFailureMessage import foundation.e.apps.testAnonymousResponseData import foundation.e.apps.util.getOrAwaitValue import foundation.e.apps.utils.Resource import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.resetMain import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.setMain import org.junit.After import org.junit.Assert import org.junit.Before import org.junit.Rule import org.junit.Test import org.mockito.Mock import org.mockito.Mockito import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) class LoginViewModelTest { private val testDispatcher = StandardTestDispatcher() @get:Rule val instantTaskExecutorRule = InstantTaskExecutorRule() @Mock lateinit var mockUserLoginUseCase: UserLoginUseCase @Mock lateinit var loginRepository: LoginSourceRepository @Before fun setUp() { MockitoAnnotations.openMocks(this) Dispatchers.setMain(testDispatcher) } @Test fun testAnonymousUserLoginStateForSuccess() = runTest{ Mockito.`when`(mockUserLoginUseCase.invoke( properties = testAnonymousRequestBodyData.properties, userAgent = testAnonymousRequestBodyData.userAgent )).thenReturn(Resource.Success(testAnonymousResponseData)) val loginViewModel = LoginViewModel(loginRepository, mockUserLoginUseCase) loginViewModel.authenticateAnonymousUser( properties = testAnonymousRequestBodyData.properties, userAgent = testAnonymousRequestBodyData.userAgent ) testDispatcher.scheduler.advanceUntilIdle() val result = loginViewModel.loginState.getOrAwaitValue() Assert.assertEquals(true, result.isLoggedIn) Assert.assertEquals(false, result.isLoading) } @Test fun testAnonymousUserLoginStateForFailure() = runTest{ Mockito.`when`(mockUserLoginUseCase.invoke( properties = testAnonymousRequestBodyData.properties, userAgent = testAnonymousRequestBodyData.userAgent )).thenReturn(Resource.Error(loginFailureMessage)) val loginViewModel = LoginViewModel(loginRepository, mockUserLoginUseCase) loginViewModel.authenticateAnonymousUser( properties = testAnonymousRequestBodyData.properties, userAgent = testAnonymousRequestBodyData.userAgent ) testDispatcher.scheduler.advanceUntilIdle() val result = loginViewModel.loginState.getOrAwaitValue() Assert.assertEquals(false, result.isLoggedIn) Assert.assertEquals(false, result.isLoading) Assert.assertEquals(loginFailureMessage, result.error) } @Test fun testAnonymousUserLoginStateForLoading() = runTest{ Mockito.`when`(mockUserLoginUseCase.invoke( properties = testAnonymousRequestBodyData.properties, userAgent = testAnonymousRequestBodyData.userAgent )).thenReturn(Resource.Loading()) val loginViewModel = LoginViewModel(loginRepository, mockUserLoginUseCase) loginViewModel.authenticateAnonymousUser( properties = testAnonymousRequestBodyData.properties, userAgent = testAnonymousRequestBodyData.userAgent ) testDispatcher.scheduler.advanceUntilIdle() val result = loginViewModel.loginState.getOrAwaitValue() Assert.assertEquals(true, result.isLoading) Assert.assertEquals(false, result.isLoggedIn) } @After fun tearDown() { Dispatchers.resetMain() } } app/src/test/java/foundation/e/apps/usecase/repository/LoginRepositoryTest.kt +10 −24 Original line number Diff line number Diff line Loading @@ -2,27 +2,20 @@ package foundation.e.apps.usecase.repository import android.content.Context import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.rules.ActivityScenarioRule import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry import app.lounge.model.AnonymousAuthDataRequestBody import app.lounge.model.AuthDataResponse import app.lounge.networking.NetworkFetching import com.aurora.gplayapi.data.models.AuthData import foundation.e.apps.domain.login.repository.LoginRepository import foundation.e.apps.testAnonymousRequestBodyData import foundation.e.apps.domain.login.repository.LoginRepositoryImpl import foundation.e.apps.testAnonymousResponseData import kotlinx.coroutines.test.runTest import org.junit.Assert import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mockito import org.mockito.MockitoAnnotations import org.robolectric.RobolectricTestRunner import retrofit2.Response import java.util.Properties @RunWith(RobolectricTestRunner::class) class LoginRepositoryTest { Loading @@ -30,7 +23,7 @@ class LoginRepositoryTest { @Mock lateinit var networkAPI: NetworkFetching lateinit var instrumentationContext: Context private lateinit var instrumentationContext: Context @Before Loading @@ -41,19 +34,12 @@ class LoginRepositoryTest { @Test fun testRequestAuthData() = runTest { Mockito.`when`(networkAPI.requestAuthData( requestBodyData )).thenReturn(AuthData("nisdande@murena.io", "")) val sut = LoginRepositoryImpl( networkAPI, instrumentationContext) val result = sut.anonymousUser(requestBodyData) Assert.assertEquals(true, result is AuthDataResponse) Assert.assertEquals("nisdande@murena.io", result.email) Mockito.`when`(networkAPI.requestAuthData(testAnonymousRequestBodyData)) .thenReturn(testAnonymousResponseData) val loginRepository = LoginRepositoryImpl(networkAPI, instrumentationContext) val result: AuthDataResponse = loginRepository.anonymousUser(testAnonymousRequestBodyData) Assert.assertNotNull(result) Assert.assertEquals("eOS@murena.io", result.email) } } private val requestBodyData = AnonymousAuthDataRequestBody( properties = Properties(), userAgent = "testUserAgent" ) No newline at end of file Loading
app/src/main/java/foundation/e/apps/domain/login/usecase/UserLoginUseCase.kt +4 −4 Original line number Diff line number Diff line Loading @@ -4,8 +4,8 @@ import app.lounge.model.AnonymousAuthDataRequestBody import app.lounge.model.AuthDataResponse import foundation.e.apps.domain.login.repository.LoginRepository import foundation.e.apps.utils.Resource import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.single import retrofit2.HttpException import java.io.IOException import java.util.Properties Loading @@ -15,10 +15,10 @@ class UserLoginUseCase @Inject constructor( private val loginRepository: LoginRepository, ) { operator fun invoke( suspend operator fun invoke( properties: Properties, userAgent: String ): Flow<Resource<AuthDataResponse>> = flow { ): Resource<AuthDataResponse> = flow { try { emit(Resource.Loading()) val userResponse: AuthDataResponse = loginRepository.anonymousUser( Loading @@ -33,5 +33,5 @@ class UserLoginUseCase @Inject constructor( } catch(e: IOException) { emit(Resource.Error("Couldn't reach server. Check your internet connection.")) } } }.single() } No newline at end of file
app/src/main/java/foundation/e/apps/presentation/login/LoginViewModel.kt +18 −18 Original line number Diff line number Diff line Loading @@ -29,8 +29,6 @@ import foundation.e.apps.domain.login.usecase.UserLoginUseCase import foundation.e.apps.ui.parentFragment.LoadingViewModel import foundation.e.apps.utils.Resource import foundation.e.apps.utils.SystemInfoProvider import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import java.util.Properties import javax.inject.Inject Loading Loading @@ -151,10 +149,11 @@ class LoginViewModel @Inject constructor( properties: Properties, userAgent: String = SystemInfoProvider.getAppBuildInfo() ) { viewModelScope.launch { userLoginUseCase( properties = properties, userAgent = userAgent ).onEach { result -> ).also { result -> when (result) { is Resource.Success -> { _loginState.value = LoginState(isLoggedIn = true) Loading @@ -168,6 +167,7 @@ class LoginViewModel @Inject constructor( _loginState.value = LoginState(isLoading = true) } } }.launchIn(viewModelScope) } } } }
app/src/test/java/foundation/e/apps/Shared.kt 0 → 100644 +15 −0 Original line number Diff line number Diff line package foundation.e.apps import app.lounge.model.AnonymousAuthDataRequestBody import com.aurora.gplayapi.data.models.AuthData import java.util.Properties val testAnonymousRequestBodyData = AnonymousAuthDataRequestBody( properties = Properties(), userAgent = "testUserAgent" ) val testAnonymousResponseData = AuthData("eOS@murena.io", "") const val loginFailureMessage = "Fail to login" No newline at end of file
app/src/test/java/foundation/e/apps/presentation/login/LoginViewModelTest.kt 0 → 100644 +108 −0 Original line number Diff line number Diff line package foundation.e.apps.presentation.login import androidx.arch.core.executor.testing.InstantTaskExecutorRule import foundation.e.apps.testAnonymousRequestBodyData import foundation.e.apps.data.login.LoginSourceRepository import foundation.e.apps.domain.login.usecase.UserLoginUseCase import foundation.e.apps.loginFailureMessage import foundation.e.apps.testAnonymousResponseData import foundation.e.apps.util.getOrAwaitValue import foundation.e.apps.utils.Resource import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.resetMain import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.setMain import org.junit.After import org.junit.Assert import org.junit.Before import org.junit.Rule import org.junit.Test import org.mockito.Mock import org.mockito.Mockito import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) class LoginViewModelTest { private val testDispatcher = StandardTestDispatcher() @get:Rule val instantTaskExecutorRule = InstantTaskExecutorRule() @Mock lateinit var mockUserLoginUseCase: UserLoginUseCase @Mock lateinit var loginRepository: LoginSourceRepository @Before fun setUp() { MockitoAnnotations.openMocks(this) Dispatchers.setMain(testDispatcher) } @Test fun testAnonymousUserLoginStateForSuccess() = runTest{ Mockito.`when`(mockUserLoginUseCase.invoke( properties = testAnonymousRequestBodyData.properties, userAgent = testAnonymousRequestBodyData.userAgent )).thenReturn(Resource.Success(testAnonymousResponseData)) val loginViewModel = LoginViewModel(loginRepository, mockUserLoginUseCase) loginViewModel.authenticateAnonymousUser( properties = testAnonymousRequestBodyData.properties, userAgent = testAnonymousRequestBodyData.userAgent ) testDispatcher.scheduler.advanceUntilIdle() val result = loginViewModel.loginState.getOrAwaitValue() Assert.assertEquals(true, result.isLoggedIn) Assert.assertEquals(false, result.isLoading) } @Test fun testAnonymousUserLoginStateForFailure() = runTest{ Mockito.`when`(mockUserLoginUseCase.invoke( properties = testAnonymousRequestBodyData.properties, userAgent = testAnonymousRequestBodyData.userAgent )).thenReturn(Resource.Error(loginFailureMessage)) val loginViewModel = LoginViewModel(loginRepository, mockUserLoginUseCase) loginViewModel.authenticateAnonymousUser( properties = testAnonymousRequestBodyData.properties, userAgent = testAnonymousRequestBodyData.userAgent ) testDispatcher.scheduler.advanceUntilIdle() val result = loginViewModel.loginState.getOrAwaitValue() Assert.assertEquals(false, result.isLoggedIn) Assert.assertEquals(false, result.isLoading) Assert.assertEquals(loginFailureMessage, result.error) } @Test fun testAnonymousUserLoginStateForLoading() = runTest{ Mockito.`when`(mockUserLoginUseCase.invoke( properties = testAnonymousRequestBodyData.properties, userAgent = testAnonymousRequestBodyData.userAgent )).thenReturn(Resource.Loading()) val loginViewModel = LoginViewModel(loginRepository, mockUserLoginUseCase) loginViewModel.authenticateAnonymousUser( properties = testAnonymousRequestBodyData.properties, userAgent = testAnonymousRequestBodyData.userAgent ) testDispatcher.scheduler.advanceUntilIdle() val result = loginViewModel.loginState.getOrAwaitValue() Assert.assertEquals(true, result.isLoading) Assert.assertEquals(false, result.isLoggedIn) } @After fun tearDown() { Dispatchers.resetMain() } }
app/src/test/java/foundation/e/apps/usecase/repository/LoginRepositoryTest.kt +10 −24 Original line number Diff line number Diff line Loading @@ -2,27 +2,20 @@ package foundation.e.apps.usecase.repository import android.content.Context import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.rules.ActivityScenarioRule import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry import app.lounge.model.AnonymousAuthDataRequestBody import app.lounge.model.AuthDataResponse import app.lounge.networking.NetworkFetching import com.aurora.gplayapi.data.models.AuthData import foundation.e.apps.domain.login.repository.LoginRepository import foundation.e.apps.testAnonymousRequestBodyData import foundation.e.apps.domain.login.repository.LoginRepositoryImpl import foundation.e.apps.testAnonymousResponseData import kotlinx.coroutines.test.runTest import org.junit.Assert import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mockito import org.mockito.MockitoAnnotations import org.robolectric.RobolectricTestRunner import retrofit2.Response import java.util.Properties @RunWith(RobolectricTestRunner::class) class LoginRepositoryTest { Loading @@ -30,7 +23,7 @@ class LoginRepositoryTest { @Mock lateinit var networkAPI: NetworkFetching lateinit var instrumentationContext: Context private lateinit var instrumentationContext: Context @Before Loading @@ -41,19 +34,12 @@ class LoginRepositoryTest { @Test fun testRequestAuthData() = runTest { Mockito.`when`(networkAPI.requestAuthData( requestBodyData )).thenReturn(AuthData("nisdande@murena.io", "")) val sut = LoginRepositoryImpl( networkAPI, instrumentationContext) val result = sut.anonymousUser(requestBodyData) Assert.assertEquals(true, result is AuthDataResponse) Assert.assertEquals("nisdande@murena.io", result.email) Mockito.`when`(networkAPI.requestAuthData(testAnonymousRequestBodyData)) .thenReturn(testAnonymousResponseData) val loginRepository = LoginRepositoryImpl(networkAPI, instrumentationContext) val result: AuthDataResponse = loginRepository.anonymousUser(testAnonymousRequestBodyData) Assert.assertNotNull(result) Assert.assertEquals("eOS@murena.io", result.email) } } private val requestBodyData = AnonymousAuthDataRequestBody( properties = Properties(), userAgent = "testUserAgent" ) No newline at end of file