From f2ce980cb1dd3b149ea286caddcef37001695e13 Mon Sep 17 00:00:00 2001 From: Paul Klauser Date: Wed, 5 Jun 2024 17:59:52 -0400 Subject: [PATCH 1/3] Move CategoryExt to basetest --- .../willowtree/vocable/settings/EditCategoriesViewModelTest.kt | 2 +- .../willowtree/vocable/basetest/utils}/presets/CategoryExt.kt | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) rename {app/src/test/java/com/willowtree/vocable => basetest/src/main/java/com/willowtree/vocable/basetest/utils}/presets/CategoryExt.kt (80%) diff --git a/app/src/test/java/com/willowtree/vocable/settings/EditCategoriesViewModelTest.kt b/app/src/test/java/com/willowtree/vocable/settings/EditCategoriesViewModelTest.kt index 85fecc1a..2274eb55 100644 --- a/app/src/test/java/com/willowtree/vocable/settings/EditCategoriesViewModelTest.kt +++ b/app/src/test/java/com/willowtree/vocable/settings/EditCategoriesViewModelTest.kt @@ -3,7 +3,7 @@ package com.willowtree.vocable.settings import app.cash.turbine.test import com.willowtree.vocable.FakeCategoriesUseCase import com.willowtree.vocable.MainDispatcherRule -import com.willowtree.vocable.presets.createStoredCategory +import com.willowtree.vocable.basetest.utils.presets.createStoredCategory import kotlinx.coroutines.flow.update import kotlinx.coroutines.test.runTest import org.junit.Assert.assertEquals diff --git a/app/src/test/java/com/willowtree/vocable/presets/CategoryExt.kt b/basetest/src/main/java/com/willowtree/vocable/basetest/utils/presets/CategoryExt.kt similarity index 80% rename from app/src/test/java/com/willowtree/vocable/presets/CategoryExt.kt rename to basetest/src/main/java/com/willowtree/vocable/basetest/utils/presets/CategoryExt.kt index 798f923d..63110976 100644 --- a/app/src/test/java/com/willowtree/vocable/presets/CategoryExt.kt +++ b/basetest/src/main/java/com/willowtree/vocable/basetest/utils/presets/CategoryExt.kt @@ -1,5 +1,6 @@ -package com.willowtree.vocable.presets +package com.willowtree.vocable.basetest.utils.presets +import com.willowtree.vocable.presets.Category import com.willowtree.vocable.utils.locale.LocalesWithText fun createStoredCategory( From 17d1a000f3c4261f64297d60ca7093b30c53d0d5 Mon Sep 17 00:00:00 2001 From: Paul Klauser Date: Wed, 5 Jun 2024 18:15:26 -0400 Subject: [PATCH 2/3] Move EditCategoriesViewModelTest to use the actual CategoriesUseCase implementation --- .../settings/EditCategoriesViewModelTest.kt | 140 ++++++++++++++++++ .../settings/EditCategoriesViewModelTest.kt | 116 --------------- 2 files changed, 140 insertions(+), 116 deletions(-) create mode 100644 app/src/androidTest/java/com/willowtree/vocable/settings/EditCategoriesViewModelTest.kt delete mode 100644 app/src/test/java/com/willowtree/vocable/settings/EditCategoriesViewModelTest.kt diff --git a/app/src/androidTest/java/com/willowtree/vocable/settings/EditCategoriesViewModelTest.kt b/app/src/androidTest/java/com/willowtree/vocable/settings/EditCategoriesViewModelTest.kt new file mode 100644 index 00000000..82001c32 --- /dev/null +++ b/app/src/androidTest/java/com/willowtree/vocable/settings/EditCategoriesViewModelTest.kt @@ -0,0 +1,140 @@ +package com.willowtree.vocable.settings + +import androidx.room.Room +import androidx.test.core.app.ApplicationProvider +import app.cash.turbine.test +import com.willowtree.vocable.CategoriesUseCase +import com.willowtree.vocable.FakeUUIDProvider +import com.willowtree.vocable.MainDispatcherRule +import com.willowtree.vocable.PhrasesUseCase +import com.willowtree.vocable.basetest.utils.FakeLocaleProvider +import com.willowtree.vocable.presets.Category +import com.willowtree.vocable.presets.PresetCategories +import com.willowtree.vocable.presets.RoomPresetCategoriesRepository +import com.willowtree.vocable.room.RoomPresetPhrasesRepository +import com.willowtree.vocable.room.RoomStoredCategoriesRepository +import com.willowtree.vocable.room.RoomStoredPhrasesRepository +import com.willowtree.vocable.room.VocableDatabase +import com.willowtree.vocable.utility.FakeDateProvider +import com.willowtree.vocable.utility.StubLegacyCategoriesAndPhrasesRepository +import kotlinx.coroutines.test.runTest +import org.junit.Assert.assertEquals +import org.junit.Rule +import org.junit.Test + +class EditCategoriesViewModelTest { + + @get:Rule + val mainDispatcherRule = MainDispatcherRule() + + private val database = Room.inMemoryDatabaseBuilder( + ApplicationProvider.getApplicationContext(), + VocableDatabase::class.java + ).build() + + private val presetCategoriesRepository = RoomPresetCategoriesRepository( + database + ) + + private val storedCategoriesRepository = RoomStoredCategoriesRepository( + database + ) + + private val presetPhrasesRepository = RoomPresetPhrasesRepository( + database.presetPhrasesDao(), + FakeDateProvider() + ) + + private val storedPhrasesRepository = RoomStoredPhrasesRepository( + database, + FakeDateProvider() + ) + + private val categoriesUseCase = CategoriesUseCase( + FakeUUIDProvider(), + FakeLocaleProvider(), + storedCategoriesRepository, + presetCategoriesRepository, + PhrasesUseCase( + StubLegacyCategoriesAndPhrasesRepository(), + storedPhrasesRepository, + presetPhrasesRepository, + FakeDateProvider(), + FakeUUIDProvider() + ) + ) + + private fun createViewModel(): EditCategoriesViewModel { + return EditCategoriesViewModel( + categoriesUseCase + ) + } + + @Test + fun categories_are_populated() = runTest { + val vm = createViewModel() + vm.refreshCategories() + + vm.categoryList.test { + assertEquals( + listOf( + Category.PresetCategory(PresetCategories.GENERAL.id, 0, false), + Category.PresetCategory(PresetCategories.BASIC_NEEDS.id, 1, false), + Category.PresetCategory(PresetCategories.PERSONAL_CARE.id, 2, false), + Category.PresetCategory(PresetCategories.CONVERSATION.id, 3, false), + Category.PresetCategory(PresetCategories.ENVIRONMENT.id, 4, false), + Category.PresetCategory(PresetCategories.USER_KEYPAD.id, 5, false), + Category.PresetCategory(PresetCategories.RECENTS.id, 6, false), + ), + awaitItem() + ) + } + } + + @Test + fun move_category_up() = runTest { + val vm = createViewModel() + vm.refreshCategories() + vm.moveCategoryUp(PresetCategories.RECENTS.id) + + vm.categoryList.test { + awaitItem() // Skip unmoved emission + assertEquals( + listOf( + Category.PresetCategory(PresetCategories.GENERAL.id, 0, false), + Category.PresetCategory(PresetCategories.BASIC_NEEDS.id, 1, false), + Category.PresetCategory(PresetCategories.PERSONAL_CARE.id, 2, false), + Category.PresetCategory(PresetCategories.CONVERSATION.id, 3, false), + Category.PresetCategory(PresetCategories.ENVIRONMENT.id, 4, false), + Category.PresetCategory(PresetCategories.RECENTS.id, 5, false), + Category.PresetCategory(PresetCategories.USER_KEYPAD.id, 6, false), + ), + awaitItem() + ) + } + } + + @Test + fun move_category_down() = runTest { + val vm = createViewModel() + vm.refreshCategories() + vm.moveCategoryDown(PresetCategories.GENERAL.id) + + vm.categoryList.test { + awaitItem() // Skip unmoved emission + assertEquals( + listOf( + Category.PresetCategory(PresetCategories.BASIC_NEEDS.id, 0, false), + Category.PresetCategory(PresetCategories.GENERAL.id, 1, false), + Category.PresetCategory(PresetCategories.PERSONAL_CARE.id, 2, false), + Category.PresetCategory(PresetCategories.CONVERSATION.id, 3, false), + Category.PresetCategory(PresetCategories.ENVIRONMENT.id, 4, false), + Category.PresetCategory(PresetCategories.USER_KEYPAD.id, 5, false), + Category.PresetCategory(PresetCategories.RECENTS.id, 6, false), + ), + awaitItem() + ) + } + } + +} \ No newline at end of file diff --git a/app/src/test/java/com/willowtree/vocable/settings/EditCategoriesViewModelTest.kt b/app/src/test/java/com/willowtree/vocable/settings/EditCategoriesViewModelTest.kt deleted file mode 100644 index 2274eb55..00000000 --- a/app/src/test/java/com/willowtree/vocable/settings/EditCategoriesViewModelTest.kt +++ /dev/null @@ -1,116 +0,0 @@ -package com.willowtree.vocable.settings - -import app.cash.turbine.test -import com.willowtree.vocable.FakeCategoriesUseCase -import com.willowtree.vocable.MainDispatcherRule -import com.willowtree.vocable.basetest.utils.presets.createStoredCategory -import kotlinx.coroutines.flow.update -import kotlinx.coroutines.test.runTest -import org.junit.Assert.assertEquals -import org.junit.Rule -import org.junit.Test - -class EditCategoriesViewModelTest { - - @get:Rule - val mainDispatcherRule = MainDispatcherRule() - - private val categoriesUseCase = FakeCategoriesUseCase() - - private fun createViewModel(): EditCategoriesViewModel { - return EditCategoriesViewModel( - categoriesUseCase - ) - } - - @Test - fun `categories are populated`() = runTest { - categoriesUseCase._categories.update { - listOf( - createStoredCategory(categoryId = "1") - ) - } - val vm = createViewModel() - vm.refreshCategories() - - vm.categoryList.test { - assertEquals( - listOf( - createStoredCategory(categoryId = "1") - ), - awaitItem() - ) - } - } - - @Test - fun `move category up`() = runTest { - categoriesUseCase._categories.update { - listOf( - createStoredCategory( - categoryId = "1", - sortOrder = 0 - ), - createStoredCategory( - categoryId = "2", - sortOrder = 1 - ) - ) - } - val vm = createViewModel() - vm.refreshCategories() - vm.moveCategoryUp("2") - - vm.categoryList.test { - assertEquals( - listOf( - createStoredCategory( - categoryId = "2", - sortOrder = 0 - ), - createStoredCategory( - categoryId = "1", - sortOrder = 1 - ) - ), - awaitItem() - ) - } - } - - @Test - fun `move category down`() = runTest { - categoriesUseCase._categories.update { - listOf( - createStoredCategory( - categoryId = "1", - sortOrder = 0 - ), - createStoredCategory( - categoryId = "2", - sortOrder = 1 - ) - ) - } - val vm = createViewModel() - vm.refreshCategories() - vm.moveCategoryDown("1") - - vm.categoryList.test { - assertEquals( - listOf( - createStoredCategory( - categoryId = "2", - sortOrder = 0 - ), - createStoredCategory( - categoryId = "1", - sortOrder = 1 - ) - ), - awaitItem() - ) - } - } - -} \ No newline at end of file From 8d5b1168944786c979be3e830e07676a9a6ef4fa Mon Sep 17 00:00:00 2001 From: Paul Klauser Date: Wed, 5 Jun 2024 18:17:09 -0400 Subject: [PATCH 3/3] Use CategoriesUseCase#moveCategoryUp/Down methods Pull this logic out of the ViewModel and leverage the use case logic we have. --- .../settings/EditCategoriesViewModel.kt | 36 ++----------------- 1 file changed, 3 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/com/willowtree/vocable/settings/EditCategoriesViewModel.kt b/app/src/main/java/com/willowtree/vocable/settings/EditCategoriesViewModel.kt index e8b7338d..b9cc4fdb 100644 --- a/app/src/main/java/com/willowtree/vocable/settings/EditCategoriesViewModel.kt +++ b/app/src/main/java/com/willowtree/vocable/settings/EditCategoriesViewModel.kt @@ -6,7 +6,6 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.willowtree.vocable.ICategoriesUseCase import com.willowtree.vocable.presets.Category -import com.willowtree.vocable.room.CategorySortOrder import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch @@ -48,45 +47,16 @@ class EditCategoriesViewModel( } fun moveCategoryUp(categoryId: String) { - viewModelScope.launch { - val categories = categoriesUseCase.categories().first() - val catIndex = categories.indexOfFirst { it.categoryId == categoryId } - if (catIndex in 1 until categories.size) { - val category = categories[catIndex] - val previousCat = categories[catIndex - 1] - swapSortOrders(categories, previousCat, category) - } + viewModelScope.launch { + categoriesUseCase.moveCategoryUp(categoryId) } } fun moveCategoryDown(categoryId: String) { viewModelScope.launch { - val categories = categoriesUseCase.categories().first() - val catIndex = categories.indexOfFirst { it.categoryId == categoryId } - if (catIndex in 0 until categories.size - 1) { - val category = categories[catIndex] - val nextCat = categories[catIndex + 1] - - swapSortOrders(categories, category, nextCat) - } + categoriesUseCase.moveCategoryDown(categoryId) } } - private suspend fun swapSortOrders( - categories: List, - leftCategory: Category, - rightCategory: Category - ) { - categoriesUseCase.updateCategorySortOrders( - categories.map { - val sortOrder = when (it.categoryId) { - rightCategory.categoryId -> leftCategory.sortOrder - leftCategory.categoryId -> rightCategory.sortOrder - else -> it.sortOrder - } - CategorySortOrder(it.categoryId, sortOrder) - } - ) - } } \ No newline at end of file