From e3998e49772596aeec2487e52b87679052db82d1 Mon Sep 17 00:00:00 2001 From: Antonio Corrales Date: Fri, 2 Aug 2024 12:25:25 +0200 Subject: [PATCH] Add unit tests for BookmarksRepository and AuthRepository --- data/build.gradle.kts | 2 + .../data/repository/AuthRepositoryTest.kt | 317 +++++++++++++++--- .../repository/BookmarksRepositoryTest.kt | 199 +++++++++++ gradle/libs.versions.toml | 1 + .../network/retrofit/NetworkBoundResource.kt | 2 +- 5 files changed, 466 insertions(+), 55 deletions(-) create mode 100644 data/src/test/java/com/desarrollodroide/data/repository/BookmarksRepositoryTest.kt diff --git a/data/build.gradle.kts b/data/build.gradle.kts index a84a63d..1c77968 100644 --- a/data/build.gradle.kts +++ b/data/build.gradle.kts @@ -84,6 +84,8 @@ dependencies { testImplementation(libs.mockito.kotlin) // Kotlin extension for Mockito to better support Kotlin features. testImplementation(libs.kotlin.coroutines.test) // Coroutines Test library for testing Kotlin coroutines. testImplementation(libs.kotlin.test.junit5) // Kotlin Test library for JUnit 5 support. + testImplementation(libs.androidx.paging.common) // Common Paging library for testing. + // Android Testing libraries androidTestImplementation ("androidx.test:core:1.5.0") // Core testing library for Android, providing API for test infrastructure. diff --git a/data/src/test/java/com/desarrollodroide/data/repository/AuthRepositoryTest.kt b/data/src/test/java/com/desarrollodroide/data/repository/AuthRepositoryTest.kt index 460b30c..c44b454 100644 --- a/data/src/test/java/com/desarrollodroide/data/repository/AuthRepositoryTest.kt +++ b/data/src/test/java/com/desarrollodroide/data/repository/AuthRepositoryTest.kt @@ -1,77 +1,286 @@ package com.desarrollodroide.data.repository import com.desarrollodroide.common.result.ErrorHandler -import com.desarrollodroide.data.UserPreferences import com.desarrollodroide.data.local.preferences.SettingsPreferenceDataSource +import com.desarrollodroide.model.Account +import com.desarrollodroide.model.User +import com.desarrollodroide.network.model.AccountDTO import com.desarrollodroide.network.model.SessionDTO import com.desarrollodroide.network.retrofit.RetrofitNetwork -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runTest import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test -import org.mockito.ArgumentMatchers.any -import org.mockito.ArgumentMatchers.anyString import org.mockito.Mock -import org.mockito.Mockito.doNothing -import org.mockito.Mockito.verify import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.toList +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue +import org.mockito.Mockito.* import retrofit2.Response +import org.mockito.kotlin.any +import org.mockito.kotlin.eq +import org.mockito.kotlin.check +import com.desarrollodroide.common.result.Result +import com.desarrollodroide.network.model.LoginResponseDTO +import com.desarrollodroide.network.model.LoginResponseMessageDTO +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.ResponseBody.Companion.toResponseBody +import org.mockito.kotlin.anyOrNull +import java.io.IOException -class AuthRepositoryTest { +@ExperimentalCoroutinesApi +class AuthRepositoryImplTest { @Mock - lateinit var apiService: RetrofitNetwork + private lateinit var apiService: RetrofitNetwork @Mock - lateinit var settingsPreferenceDataSource: SettingsPreferenceDataSource + private lateinit var settingsPreferenceDataSource: SettingsPreferenceDataSource @Mock - lateinit var errorHandler: ErrorHandler + private lateinit var errorHandler: ErrorHandler - private lateinit var authRepositoryImpl: AuthRepositoryImpl + private lateinit var authRepository: AuthRepositoryImpl @BeforeEach - fun setUp() { - MockitoAnnotations.initMocks(this) - authRepositoryImpl = AuthRepositoryImpl(apiService, settingsPreferenceDataSource, errorHandler) + fun setup() { + MockitoAnnotations.openMocks(this) + authRepository = AuthRepositoryImpl(apiService, settingsPreferenceDataSource, errorHandler) } -// -// @Test -// fun `sendLogin saves user on successful login`() = runBlocking { -// val username = "user" -// val password = "pass" -// val serverUrl = "http://test.com" -// val sessionDTO = SessionDTO("sessionId", null, null) -// val userPreferences = UserPreferences.newBuilder() -// .setUsername(username) -// .setOwner(false) -// .setPassword(password) -// .setSession("sessionId") -// .setUrl(serverUrl) -// .setRememberPassword(true) -// .build() -// -// `when`(apiService.sendLogin(anyString(), anyString())).thenReturn(Response.success(sessionDTO)) -// doNothing().`when`(settingsPreferenceDataSource).saveUser(any(UserPreferences::class.java), anyString(), anyString()) -// -// authRepositoryImpl.sendLogin(username, password, serverUrl).collect { /* AquĆ­ puedes hacer assertions sobre el resultado */ } -// -//// verify(settingsPreferenceDataSource).saveUser( -//// argThat { session == "sessionId" && url == serverUrl && this.password == password }, -//// eq(serverUrl), -//// eq(password) -//// ) -// } - -// @Test -// fun `sendLogout resets user data on successful logout`() = runBlocking { -// val serverUrl = "http://test.com" -// val xSession = "sessionId" -// -// `when`(apiService.sendLogout(anyString(), anyString())).thenReturn(Response.success("Logged out")) -// -// authRepositoryImpl.sendLogout(serverUrl, xSession).collect { /* Here you can assert the result */ } -// -// verify(settingsPreferenceDataSource).resetUser() -// } -} \ No newline at end of file + + @Test + fun `sendLogin should emit Loading and Success states when API call is successful`() = runTest { + // Arrange + val username = "testUser" + val password = "testPassword" + val serverUrl = "http://test.com" + val sessionDTO = SessionDTO( + "testSession", + "testToken", + AccountDTO(1, username, isOwner = false, isLegacyApi = true) + ) + val expectedUser = + User("testToken", "testSession", Account(1, username, password, false, serverUrl, true)) + + `when`(apiService.sendLogin(anyString(), any())).thenReturn(Response.success(sessionDTO)) + `when`(settingsPreferenceDataSource.getUser()).thenReturn(flowOf(expectedUser)) + + // Act + val results = authRepository.sendLogin(username, password, serverUrl).toList() + + // Assert + assertEquals(3, results.size, "Expected 3 emitted results") + assertTrue(results[0] is Result.Loading && results[0].data == null) + assertTrue(results[1] is Result.Loading && results[1].data != null) + assertTrue(results[2] is Result.Success && results[2].data == expectedUser) + + verify(settingsPreferenceDataSource).saveUser(any(), eq(serverUrl), eq(password)) + verify(apiService).sendLogin(check { it.endsWith("/api/login") }, any()) + } + + @Test + fun `sendLogin should emit Loading and Error states when API call fails`() = runTest { + // Arrange + val username = "testUser" + val password = "testPassword" + val serverUrl = "http://test.com" + val errorMessage = "Invalid credentials" + val errorResponseBody = errorMessage.toResponseBody("text/plain".toMediaTypeOrNull()) + + `when`(apiService.sendLogin(anyString(), any())).thenReturn(Response.error(400, errorResponseBody)) + `when`(errorHandler.getApiError(eq(400), anyOrNull(), eq(errorMessage))).thenReturn(Result.ErrorType.HttpError(statusCode = 400, message = errorMessage)) + `when`(settingsPreferenceDataSource.getUser()).thenReturn(flowOf()) // Ensure a valid empty flow is returned + + // Act + val results = authRepository.sendLogin(username, password, serverUrl).toList() + + // Debugging: Print results + results.forEachIndexed { index, result -> + println("Result $index: $result") + if (result is Result.Error) { + println("Result $index error: '${result.error?.message}'") + } else if (result is Result.Loading) { + println("Result $index loading data: '${result.data}'") + } + } + + // Assert + assertEquals(3, results.size, "Expected 3 emitted results") + assertTrue(results[0] is Result.Loading && results[0].data == null) + assertTrue(results[1] is Result.Loading && results[1].data == null) + assertTrue(results[2] is Result.Error && (results[2] as Result.Error).error is Result.ErrorType.HttpError) + assertEquals((results[2] as Result.Error).error?.message, errorMessage) + + verify(apiService).sendLogin(check { it.endsWith("/api/login") }, any()) + } + + @Test + fun `sendLogin should emit Loading and Error states when network error occurs`() = runTest { + // Arrange + val username = "testUser" + val password = "testPassword" + val serverUrl = "http://test.com" + val networkErrorMessage = "Network error" + val ioException = IOException(networkErrorMessage) + + `when`(apiService.sendLogin(anyString(), any())).thenAnswer { invocation -> + throw ioException + } + + `when`(errorHandler.getError(ioException)).thenReturn(Result.ErrorType.IOError(ioException)) + `when`(settingsPreferenceDataSource.getUser()).thenReturn(flowOf()) // Ensure a valid empty flow is returned + + // Act + val results = authRepository.sendLogin(username, password, serverUrl).toList() + + // Assert + assertEquals(3, results.size, "Expected 3 emitted results") + assertTrue(results[0] is Result.Loading && results[0].data == null) + assertTrue(results[1] is Result.Loading && results[1].data == null) + assertTrue(results[2] is Result.Error && (results[2] as Result.Error).error is Result.ErrorType.IOError) + assertEquals(networkErrorMessage, (results[2] as Result.Error).error?.throwable?.message) + + verify(apiService).sendLogin(check { it.endsWith("/api/login") }, any()) + } + + @Test + fun `sendLogin should not call saveUser when API call fails`() = runTest { + // Arrange + val username = "testUser" + val password = "testPassword" + val serverUrl = "http://test.com" + val errorMessage = "Invalid credentials" + val errorResponseBody = errorMessage.toResponseBody("text/plain".toMediaTypeOrNull()) + + `when`(apiService.sendLogin(anyString(), any())).thenReturn(Response.error(400, errorResponseBody)) + `when`(errorHandler.getApiError(eq(400), anyOrNull(), eq(errorMessage))).thenReturn(Result.ErrorType.HttpError(statusCode = 400, message = errorMessage)) + `when`(settingsPreferenceDataSource.getUser()).thenReturn(flowOf()) // Ensure a valid empty flow is returned + + // Act + val results = authRepository.sendLogin(username, password, serverUrl).toList() + + // Assert + assertEquals(3, results.size, "Expected 3 emitted results") + assertTrue(results[0] is Result.Loading && results[0].data == null) + assertTrue(results[1] is Result.Loading && results[1].data == null) + assertTrue(results[2] is Result.Error && (results[2] as Result.Error).error is Result.ErrorType.HttpError) + assertEquals((results[2] as Result.Error).error?.message, errorMessage) + + verify(apiService).sendLogin(check { it.endsWith("/api/login") }, any()) + verify(settingsPreferenceDataSource, never()).saveUser(any(), anyString(), anyString()) + } + + @Test + fun `sendLogout should emit Loading, Loading with data, and Success states when API call is successful`() = runTest { + // Arrange + val serverUrl = "http://test.com" + val xSession = "testSession" + val logoutResponse = "Logout successful" // La respuesta esperada del servidor + + `when`(apiService.sendLogout(anyString(), anyString())).thenReturn(Response.success(logoutResponse)) + + // Act + val results = authRepository.sendLogout(serverUrl, xSession).toList() + + // Assert + assertEquals(3, results.size, "Expected 3 emitted results") + assertTrue(results[0] is Result.Loading && results[0].data == null, "First result should be Loading with null data") + assertTrue(results[1] is Result.Loading && results[1].data == "", "Second result should be Loading with empty data") + assertTrue(results[2] is Result.Success && (results[2] as Result.Success).data == "") { + "Expected third result to be Success with empty data after resetUser, but was '${(results[2] as Result.Success).data}'" + } + + verify(settingsPreferenceDataSource).resetUser() + verify(apiService).sendLogout(check { it.endsWith("/api/logout") }, eq(xSession)) + } + + @Test + fun `sendLogout should emit Loading and Error states when API call fails`() = runTest { + // Arrange + val serverUrl = "http://test.com" + val xSession = "testSession" + val errorMessage = "Logout failed" + val errorResponseBody = errorMessage.toResponseBody("text/plain".toMediaTypeOrNull()) + + `when`(apiService.sendLogout(anyString(), anyString())).thenReturn(Response.error(400, errorResponseBody)) + `when`(errorHandler.getApiError(eq(400), anyOrNull(), eq(errorMessage))).thenReturn(Result.ErrorType.HttpError(statusCode = 400, message = errorMessage)) + + // Act + val results = authRepository.sendLogout(serverUrl, xSession).toList() + + // Assert + assertEquals(3, results.size, "Expected 3 emitted results") + assertTrue(results[0] is Result.Loading && results[0].data == null, "First result should be Loading with null data") + assertTrue(results[1] is Result.Loading && results[1].data == "", "Second result should be Loading with empty string data") + assertTrue(results[2] is Result.Error && (results[2] as Result.Error).error is Result.ErrorType.HttpError, "Third result should be Error with HttpError type") + assertEquals((results[2] as Result.Error).error?.message, errorMessage, "Error message should match expected message") + + verify(apiService).sendLogout(check { it.endsWith("/api/logout") }, eq(xSession)) + } + + @Test + fun `sendLogout should emit Loading and Error states when network error occurs`() = runTest { + // Arrange + val serverUrl = "http://test.com" + val xSession = "testSession" + val networkErrorMessage = "Network error" + val ioException = IOException(networkErrorMessage) + + `when`(apiService.sendLogout(anyString(), anyString())).thenAnswer { invocation -> + throw ioException + } + + `when`(errorHandler.getError(ioException)).thenReturn(Result.ErrorType.IOError(ioException)) + + // Act + val results = authRepository.sendLogout(serverUrl, xSession).toList() + + // Assert + assertEquals(3, results.size, "Expected 3 emitted results") + assertTrue(results[0] is Result.Loading && results[0].data == null) + assertTrue(results[1] is Result.Loading && results[1].data == "") + assertTrue(results[2] is Result.Error && (results[2] as Result.Error).error is Result.ErrorType.IOError) + assertEquals(networkErrorMessage, (results[2] as Result.Error).error?.throwable?.message) + + verify(apiService).sendLogout(check { it.endsWith("/api/logout") }, eq(xSession)) + } + + @Test + fun `sendLoginV1 should emit Loading and Success states when API call is successful`() = runTest { + // Arrange + val username = "testUser" + val password = "testPassword" + val serverUrl = "http://test.com" + val loginResponseMessageDTO = LoginResponseMessageDTO( + expires = null, + session = null, + token = "testToken" + ) + val loginResponseDTO = LoginResponseDTO( + ok = true, + message = loginResponseMessageDTO, + error = null + ) + val expectedUser = + User("testToken", "testSession", Account(1, username, password, false, serverUrl, true)) + + `when`(apiService.sendLoginV1(anyString(), any())).thenReturn(Response.success(loginResponseDTO)) + `when`(settingsPreferenceDataSource.getUser()).thenReturn(flowOf(expectedUser)) + + // Act + val results = authRepository.sendLoginV1(username, password, serverUrl).toList() + + // Assert + assertEquals(3, results.size, "Expected 3 emitted results") + assertTrue(results[0] is Result.Loading && results[0].data == null) + assertTrue(results[1] is Result.Loading && results[1].data != null) + assertTrue(results[2] is Result.Success && results[2].data == expectedUser) + + verify(settingsPreferenceDataSource).saveUser(any(), eq(serverUrl), eq(password)) + verify(apiService).sendLoginV1(check { it.endsWith("/api/v1/auth/login") }, any()) + } +} + diff --git a/data/src/test/java/com/desarrollodroide/data/repository/BookmarksRepositoryTest.kt b/data/src/test/java/com/desarrollodroide/data/repository/BookmarksRepositoryTest.kt new file mode 100644 index 0000000..f4e7b74 --- /dev/null +++ b/data/src/test/java/com/desarrollodroide/data/repository/BookmarksRepositoryTest.kt @@ -0,0 +1,199 @@ +package com.desarrollodroide.data.repository + +import com.desarrollodroide.common.result.ErrorHandler +import com.desarrollodroide.network.retrofit.RetrofitNetwork +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runTest +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.mockito.Mock +import org.mockito.Mockito.`when` +import org.mockito.MockitoAnnotations +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.toList +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue +import org.mockito.Mockito.* +import retrofit2.Response +import org.mockito.kotlin.eq +import org.mockito.kotlin.check +import com.desarrollodroide.common.result.Result +import com.desarrollodroide.data.local.room.dao.BookmarksDao +import com.desarrollodroide.data.local.room.entity.BookmarkEntity +import com.desarrollodroide.data.mapper.toDomainModel +import com.desarrollodroide.model.Bookmark +import com.desarrollodroide.network.model.BookmarkDTO +import com.desarrollodroide.network.model.BookmarksDTO +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.ResponseBody.Companion.toResponseBody +import org.mockito.kotlin.anyOrNull +import java.io.IOException + +@ExperimentalCoroutinesApi +class BookmarksRepositoryTest { + + @Mock + private lateinit var apiService: RetrofitNetwork + + @Mock + private lateinit var bookmarksDao: BookmarksDao + + @Mock + private lateinit var errorHandler: ErrorHandler + + private lateinit var bookmarksRepository: BookmarksRepositoryImpl + + @BeforeEach + fun setup() { + MockitoAnnotations.openMocks(this) + bookmarksRepository = BookmarksRepositoryImpl(apiService, bookmarksDao, errorHandler) + } + + @Test + fun `getBookmarks should emit Loading and Success states when API call is successful`() = runTest { + // Arrange + val xSessionId = "testSessionId" + val serverUrl = "http://test.com" + val bookmarksDTO = BookmarksDTO( + maxPage = 1, + page = 1, + bookmarks = listOf( + BookmarkDTO(1, "http://bookmark1.com", "Bookmark 1", "Excerpt 1", "Author 1", 1, "2023-01-01", "http://image1.com", true, true, true, listOf(), true, true), + BookmarkDTO(2, "http://bookmark2.com", "Bookmark 2", "Excerpt 2", "Author 2", 1, "2023-01-02", "http://image2.com", true, true, true, listOf(), true, true) + ) + ) + val bookmarkEntities = listOf( + BookmarkEntity(1, "http://bookmark1.com", "Bookmark 1", "Excerpt 1", "Author 1", 1, "2023-01-01", "http://image1.com", true, true, true, listOf(), true, true), + BookmarkEntity(2, "http://bookmark2.com", "Bookmark 2", "Excerpt 2", "Author 2", 1, "2023-01-02", "http://image2.com", true, true, true, listOf(), true, true) + ) + val expectedBookmarks = bookmarkEntities.map { it.toDomainModel() } + + `when`(apiService.getBookmarks(eq(xSessionId), anyString())).thenReturn(Response.success(bookmarksDTO)) + `when`(bookmarksDao.getAll()).thenReturn(flowOf(bookmarkEntities)) + + // Act + val results = bookmarksRepository.getBookmarks(xSessionId, serverUrl).toList() + + // Assert + assertEquals(3, results.size, "Expected 3 emitted results") + assertTrue(results[0] is Result.Loading && results[0].data == null) + assertTrue(results[1] is Result.Loading && results[1].data != null) + assertTrue(results[2] is Result.Success && results[2].data == expectedBookmarks) + + verify(bookmarksDao).deleteAll() + verify(bookmarksDao).insertAll(bookmarkEntities) + verify(apiService).getBookmarks(eq(xSessionId), check { it.endsWith("/api/bookmarks") }) + } + + @Test + fun `getBookmarks should emit Loading and Error states when API call fails`() = runTest { + // Arrange + val xSessionId = "testSessionId" + val serverUrl = "http://test.com" + val errorMessage = "Error fetching bookmarks" + val errorResponseBody = errorMessage.toResponseBody("text/plain".toMediaTypeOrNull()) + + `when`(apiService.getBookmarks(eq(xSessionId), anyString())).thenReturn(Response.error(400, errorResponseBody)) + `when`(errorHandler.getApiError(eq(400), anyOrNull(), eq(errorMessage))).thenReturn(Result.ErrorType.HttpError(statusCode = 400, message = errorMessage)) + `when`(bookmarksDao.getAll()).thenReturn(flowOf(emptyList())) // Ensure a valid empty flow is returned + + // Act + val results = bookmarksRepository.getBookmarks(xSessionId, serverUrl).toList() + + // Assert + assertEquals(3, results.size, "Expected 3 emitted results") + assertTrue(results[0] is Result.Loading && results[0].data == null) + assertTrue(results[1] is Result.Loading && results[1].data == emptyList()) + assertTrue(results[2] is Result.Error && (results[2] as Result.Error).error is Result.ErrorType.HttpError) + assertEquals((results[2] as Result.Error).error?.message, errorMessage) + + verify(apiService).getBookmarks(eq(xSessionId), check { it.endsWith("/api/bookmarks") }) + } + + @Test + fun `getBookmarks should emit Loading and Error states when network error occurs`() = runTest { + // Arrange + val xSessionId = "testSessionId" + val serverUrl = "http://test.com" + val networkErrorMessage = "Network error" + val ioException = IOException(networkErrorMessage) + + `when`(apiService.getBookmarks(eq(xSessionId), anyString())).thenAnswer { throw ioException } + `when`(errorHandler.getError(ioException)).thenReturn(Result.ErrorType.IOError(ioException)) + `when`(bookmarksDao.getAll()).thenReturn(flowOf(emptyList())) // Ensure a valid empty flow is returned + + // Act + val results = bookmarksRepository.getBookmarks(xSessionId, serverUrl).toList() + + // Assert + assertEquals(3, results.size, "Expected 3 emitted results") + assertTrue(results[0] is Result.Loading && results[0].data == null) + assertTrue(results[1] is Result.Loading && results[1].data == emptyList()) + assertTrue(results[2] is Result.Error && (results[2] as Result.Error).error is Result.ErrorType.IOError) + assertEquals(networkErrorMessage, (results[2] as Result.Error).error?.throwable?.message) + + verify(apiService).getBookmarks(eq(xSessionId), check { it.endsWith("/api/bookmarks") }) + } + + @Test + fun `getBookmarks should emit Loading and Error states when API call fails with HTTP error`() = runTest { + // Arrange + val xSessionId = "testSessionId" + val serverUrl = "http://test.com" + val errorMessage = "HTTP error" + val errorResponseBody = errorMessage.toResponseBody("text/plain".toMediaTypeOrNull()) + + `when`(apiService.getBookmarks(eq(xSessionId), anyString())).thenReturn(Response.error(400, errorResponseBody)) + `when`(errorHandler.getApiError(eq(400), anyOrNull(), eq(errorMessage))).thenReturn(Result.ErrorType.HttpError(statusCode = 400, message = errorMessage)) + `when`(bookmarksDao.getAll()).thenReturn(flowOf(emptyList())) // Ensure a valid empty flow is returned + + // Act + val results = bookmarksRepository.getBookmarks(xSessionId, serverUrl).toList() + + // Assert + assertEquals(3, results.size, "Expected 3 emitted results") + assertTrue(results[0] is Result.Loading && results[0].data == null) + assertTrue(results[1] is Result.Loading && results[1].data == emptyList()) + assertTrue(results[2] is Result.Error && (results[2] as Result.Error).error is Result.ErrorType.HttpError) + assertEquals((results[2] as Result.Error).error?.message, errorMessage) + + verify(apiService).getBookmarks(eq(xSessionId), check { it.endsWith("/api/bookmarks") }) + } + +// @Test +// fun `getPagingBookmarks should return paginated data when API call is successful`() = runTest { +// // Arrange +// val xSessionId = "testSessionId" +// val serverUrl = "http://test.com" +// val searchText = "test" +// val tags = listOf() +// val saveToLocal = true +// val bookmarksDTO = BookmarksDTO( +// maxPage = 1, +// page = 1, +// bookmarks = listOf( +// BookmarkDTO(1, "http://bookmark1.com", "Bookmark 1", "Excerpt 1", "Author 1", 1, "2023-01-01", "http://image1.com", true, true, true, listOf(), true, true), +// BookmarkDTO(2, "http://bookmark2.com", "Bookmark 2", "Excerpt 2", "Author 2", 1, "2023-01-02", "http://image2.com", true, true, true, listOf(), true, true) +// ) +// ) +// val bookmarkEntities = listOf( +// BookmarkEntity(1, "http://bookmark1.com", "Bookmark 1", "Excerpt 1", "Author 1", 1, "2023-01-01", "http://image1.com", true, true, true, listOf(), true, true), +// BookmarkEntity(2, "http://bookmark2.com", "Bookmark 2", "Excerpt 2", "Author 2", 1, "2023-01-02", "http://image2.com", true, true, true, listOf(), true, true) +// ) +// val expectedBookmarks = bookmarkEntities.map { it.toDomainModel() } +// +// `when`(apiService.getPagingBookmarks(eq(xSessionId), anyString())).thenReturn(Response.success(bookmarksDTO)) +// `when`(bookmarksDao.getAll()).thenReturn(flowOf(bookmarkEntities)) +// +// // Act +// val pager = Pager( +// config = PagingConfig(pageSize = 20, prefetchDistance = 2), +// pagingSourceFactory = { BookmarkPagingSource(apiService, bookmarksDao, serverUrl, xSessionId, searchText, tags, saveToLocal) } +// ).flow +// +// val snapshot = pager.first() +// +// // Assert +// assertEquals(expectedBookmarks, snapshot) +// } +} \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9e5bcb6..d9a76d9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -49,6 +49,7 @@ androidx-datastore-core = { module = "androidx.datastore:datastore-core", versio androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastorePreferences" } androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "androidxnavigation" } androidx-paging-compose = { module = "androidx.paging:paging-compose", version.ref = "pagingCompose" } +androidx-paging-common = { module = "androidx.paging:paging-common", version.ref = "pagingCompose" } junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junitJupiter" } junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junitJupiter" } diff --git a/network/src/main/java/com/desarrollodroide/network/retrofit/NetworkBoundResource.kt b/network/src/main/java/com/desarrollodroide/network/retrofit/NetworkBoundResource.kt index 2a64ed6..65a1ab2 100644 --- a/network/src/main/java/com/desarrollodroide/network/retrofit/NetworkBoundResource.kt +++ b/network/src/main/java/com/desarrollodroide/network/retrofit/NetworkBoundResource.kt @@ -49,7 +49,7 @@ abstract class NetworkBoundResource( } } catch (e: Exception) { if (e !is CancellationException) { - Log.v("NetworkBoundResource", "Error: ${e.message}") + println("NetworkBoundResource: Error: ${e.message}") emit(Result.Error(errorHandler.getError(e))) } }