Migrated bookmarks locations to Kotlin and adapt room database (#6148)

* Rename .java to .kt

* Refactor: Migrate bookmark location logic to Kotlin

This commit migrates the bookmark location logic to Kotlin, enhancing code maintainability and readability.

-   Removes the `BookmarkLocationsContentProvider`, `BookmarkLocationsController`, and `BookmarkLocationsDao` Java classes.
-   Creates `BookmarkLocationsDao.kt` and `BookmarkLocationsContentProvider.kt` in Kotlin.
-   Migrates the logic from `BookmarkLocationsFragment.java` to `BookmarkLocationsFragment.kt`.
-   Updates test files to reflect these changes.
-   Addresses associated code review comments.

* Refactor: Migrate to Room Database for Bookmark Locations

This commit migrates the bookmark locations functionality from a custom content provider to Room database.

Key changes:

*   **Removal of `BookmarkLocationsContentProvider`:** This class, which previously handled data storage, has been removed.
*   **Introduction of `BookmarksLocations`:** This data class now represents a bookmarked location, serving as the Room entity.
*   **Creation of `BookmarkLocationsDao`:** This Room DAO handles database interactions for bookmark locations, including:
    *   Adding, deleting, and querying bookmarked locations.
    *   Checking if a location is already bookmarked.
    *   Updating the bookmark status of a location.
    *   Retrieving all bookmarked locations as `Place` objects.
*   **`BookmarkLocationsViewModel`:** Added to manage the data layer for bookmark locations
*   **`NearbyUtil`:** Created a Util class for Nearby to manage the bookmark locations.
*   **Updates in `PlaceAdapter` and `PlaceAdapterDelegate`:** These classes have been modified to work with the new Room-based data layer.
*   **Updates in `AppDatabase`:** The database now includes `BookmarksLocations` as an entity and exposes the `bookmarkLocationsDao`.
*   **Updates in `FragmentBuilderModule` and `CommonsApplicationModule`**: for DI
*   **Removal of `DBOpenHelper` upgrade for locations**: as it is no longer needed
* **Updates in `NearbyParentFragmentPresenter`**: refactored the logic to use the dao functions
* **Updates in `NearbyParentFragment`**: refactored the logic to use the util and dao functions
* **Update in `BookmarkLocationsController`**: removed as its no longer needed
* **Add `toPlace` and `toBookmarksLocations`**: extension functions to map between data class and entities
* **Update in `CommonsApplication`**: to remove old db table.

* Refactor: Improve bookmark location handling and update database version

This commit includes the following changes:

-   Updates the database version to 20.
-   Refactors bookmark location handling within `NearbyParentFragment` to improve logic and efficiency.
-   Introduces `getBookmarkLocationExists` in `NearbyUtil` to directly update bookmark icons in the bottom sheet adapter.
-   Removes unused provider.
-   Adjusts `BookmarkLocationsFragment`'s `PlaceAdapter` to use `lifecycleScope` for better coroutine management.
-   Refactors `updateBookmarkLocation` in `NearbyParentFragmentPresenter`.

* Toggle bookmark icon in BottomSheetAdapter instead of finding the location each time in the bookmark

* Update bookmark button image in `BottomSheetAdapter`
* Add new toggle function to `BottomSheetAdapter`
* Call the toggle function in `NearbyParentFragment`

* Refactor: Load bookmarked locations using Flow

*   `BookmarkLocationsController`: Changed to use `Flow` to load bookmarked locations.
*   `BookmarkLocationsDao`: Changed to return `Flow` of bookmark location instead of a list.
*   `BookmarkLocationsFragment`: Used `LifecycleScope` to collect data from flow and display it.
*   Removed unused `getAllBookmarkLocations()` from `BookmarkLocationsViewModel`.
*   Used `map` in `BookmarkLocationsDao` to convert from `BookmarksLocations` to `Place` list.

* Loading locations data in fragment

*   BookmarkLocationsController: Changed `loadFavoritesLocations` to be a suspend function.
*   BookmarkLocationsFragment: Updated the `initList` function to call the controller's suspend function.
*   BookmarkLocationsDao: Changed `getAllBookmarksLocations` and `getAllBookmarksLocationsPlace` to be suspend functions.

* Refactor BookmarkLocationControllerTest and related files to use coroutines

*  Migrated `bookmarkDao!!.getAllBookmarksLocations()` to `bookmarkDao!!.getAllBookmarksLocationsPlace()` and added `runBlocking`
*  Added `runBlocking` for `loadBookmarkedLocations()` and `testInitNonEmpty()`
*  Added `runBlocking` for `getAllBookmarksLocations()` and update `updateMapMarkers`

These changes improve the test structure by ensuring the database functions are executed within a coroutine context.

* Refactor BookmarkLocationsFragment and add tests for BookmarkLocationsDao

*   Moved `initList` to `BookmarkLocationsFragment` for better lifecycle handling.
*   Added test case for `BookmarkLocationsFragment`'s onResume.
*   Added test cases for `BookmarkLocationsDao` operations like adding, retrieving, finding, deleting and updating bookmarks.

* Refactor BookmarkLocationsFragment to load favorites only when view is not null

* BookmarkLocationsFragment: load favorites locations only when view is not null.
* BookmarkLocationsFragmentTest: added spy and verify to test onResume() call initList() method.

* Refactor database and add migration

*   `AppDatabase`: Updated to use room migration.
*   `CommonsApplicationModule`: added migration from version 19 to 20 to `appDatabase`

* Rename .java to .kt

* Refactor: Migrate bookmark location logic to Kotlin

This commit migrates the bookmark location logic to Kotlin, enhancing code maintainability and readability.

-   Removes the `BookmarkLocationsContentProvider`, `BookmarkLocationsController`, and `BookmarkLocationsDao` Java classes.
-   Creates `BookmarkLocationsDao.kt` and `BookmarkLocationsContentProvider.kt` in Kotlin.
-   Migrates the logic from `BookmarkLocationsFragment.java` to `BookmarkLocationsFragment.kt`.
-   Updates test files to reflect these changes.
-   Addresses associated code review comments.

* Refactor: Migrate to Room Database for Bookmark Locations

This commit migrates the bookmark locations functionality from a custom content provider to Room database.

Key changes:

*   **Removal of `BookmarkLocationsContentProvider`:** This class, which previously handled data storage, has been removed.
*   **Introduction of `BookmarksLocations`:** This data class now represents a bookmarked location, serving as the Room entity.
*   **Creation of `BookmarkLocationsDao`:** This Room DAO handles database interactions for bookmark locations, including:
    *   Adding, deleting, and querying bookmarked locations.
    *   Checking if a location is already bookmarked.
    *   Updating the bookmark status of a location.
    *   Retrieving all bookmarked locations as `Place` objects.
*   **`BookmarkLocationsViewModel`:** Added to manage the data layer for bookmark locations
*   **`NearbyUtil`:** Created a Util class for Nearby to manage the bookmark locations.
*   **Updates in `PlaceAdapter` and `PlaceAdapterDelegate`:** These classes have been modified to work with the new Room-based data layer.
*   **Updates in `AppDatabase`:** The database now includes `BookmarksLocations` as an entity and exposes the `bookmarkLocationsDao`.
*   **Updates in `FragmentBuilderModule` and `CommonsApplicationModule`**: for DI
*   **Removal of `DBOpenHelper` upgrade for locations**: as it is no longer needed
* **Updates in `NearbyParentFragmentPresenter`**: refactored the logic to use the dao functions
* **Updates in `NearbyParentFragment`**: refactored the logic to use the util and dao functions
* **Update in `BookmarkLocationsController`**: removed as its no longer needed
* **Add `toPlace` and `toBookmarksLocations`**: extension functions to map between data class and entities
* **Update in `CommonsApplication`**: to remove old db table.

* Refactor: Improve bookmark location handling and update database version

This commit includes the following changes:

-   Updates the database version to 20.
-   Refactors bookmark location handling within `NearbyParentFragment` to improve logic and efficiency.
-   Introduces `getBookmarkLocationExists` in `NearbyUtil` to directly update bookmark icons in the bottom sheet adapter.
-   Removes unused provider.
-   Adjusts `BookmarkLocationsFragment`'s `PlaceAdapter` to use `lifecycleScope` for better coroutine management.
-   Refactors `updateBookmarkLocation` in `NearbyParentFragmentPresenter`.

* Toggle bookmark icon in BottomSheetAdapter instead of finding the location each time in the bookmark

* Update bookmark button image in `BottomSheetAdapter`
* Add new toggle function to `BottomSheetAdapter`
* Call the toggle function in `NearbyParentFragment`

* Refactor: Load bookmarked locations using Flow

*   `BookmarkLocationsController`: Changed to use `Flow` to load bookmarked locations.
*   `BookmarkLocationsDao`: Changed to return `Flow` of bookmark location instead of a list.
*   `BookmarkLocationsFragment`: Used `LifecycleScope` to collect data from flow and display it.
*   Removed unused `getAllBookmarkLocations()` from `BookmarkLocationsViewModel`.
*   Used `map` in `BookmarkLocationsDao` to convert from `BookmarksLocations` to `Place` list.

* Loading locations data in fragment

*   BookmarkLocationsController: Changed `loadFavoritesLocations` to be a suspend function.
*   BookmarkLocationsFragment: Updated the `initList` function to call the controller's suspend function.
*   BookmarkLocationsDao: Changed `getAllBookmarksLocations` and `getAllBookmarksLocationsPlace` to be suspend functions.

* Refactor BookmarkLocationControllerTest and related files to use coroutines

*  Migrated `bookmarkDao!!.getAllBookmarksLocations()` to `bookmarkDao!!.getAllBookmarksLocationsPlace()` and added `runBlocking`
*  Added `runBlocking` for `loadBookmarkedLocations()` and `testInitNonEmpty()`
*  Added `runBlocking` for `getAllBookmarksLocations()` and update `updateMapMarkers`

These changes improve the test structure by ensuring the database functions are executed within a coroutine context.

* Refactor BookmarkLocationsFragment and add tests for BookmarkLocationsDao

*   Moved `initList` to `BookmarkLocationsFragment` for better lifecycle handling.
*   Added test case for `BookmarkLocationsFragment`'s onResume.
*   Added test cases for `BookmarkLocationsDao` operations like adding, retrieving, finding, deleting and updating bookmarks.

* Refactor BookmarkLocationsFragment to load favorites only when view is not null

* BookmarkLocationsFragment: load favorites locations only when view is not null.
* BookmarkLocationsFragmentTest: added spy and verify to test onResume() call initList() method.

* Refactor database and add migration

*   `AppDatabase`: Updated to use room migration.
*   `CommonsApplicationModule`: added migration from version 19 to 20 to `appDatabase`

* Resolve conflicts and attach the `commons.db` with `common_room.db` during the migration to persist the data

* Refactor database migration to handle null values and use direct insertion

*   Modify the database migration from version 19 to 20 to properly handle null values and use direct data insertion.
*   Create a new table `bookmarks_locations` with `NOT NULL` constraints.
*   Directly insert data into the new table from old database, safely handling `NULL` values by using `DEFAULT` empty string value.
*   Close old database cursor and the database connection.
* Drop the old `bookmarksLocations` table.

* Refactor database schema to delete `bookmarksLocations` table and migrate data

*   Delete `bookmarksLocations` table from the database during schema upgrade
*   Migrate data from `bookmarksLocations` to `bookmarks_locations` in new schema
*   Add `INSERT OR REPLACE` to prevent duplication during migration
*   Delete `CONTRIBUTIONS_TABLE` and `BOOKMARKS_LOCATIONS` in the application start-up to have a fresh DB for first start-up after update

* Update sqlite-based database version to 22.

* Update sqlite-based database version to 22.

* Refactor CommonsApplicationModule to utilize application context

* Initialize and use application context directly

* Utilize lateinit for application context

* Added line breaks for improved readability.

---------

Co-authored-by: Nicolas Raoul <nicolas.raoul@gmail.com>
This commit is contained in:
Saifuddin Adenwala 2025-02-24 19:28:26 +05:30 committed by GitHub
parent 1c4797d3aa
commit 1c7dce9e12
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 702 additions and 946 deletions

View file

@ -7,6 +7,8 @@ import android.database.MatrixCursor
import android.database.sqlite.SQLiteDatabase
import android.net.Uri
import android.os.RemoteException
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
import com.nhaarman.mockitokotlin2.any
import com.nhaarman.mockitokotlin2.anyOrNull
import com.nhaarman.mockitokotlin2.argumentCaptor
@ -18,36 +20,20 @@ import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.verify
import com.nhaarman.mockitokotlin2.whenever
import fr.free.nrw.commons.TestCommonsApplication
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsContentProvider.BASE_URI
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_CATEGORY
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_COMMONS_LINK
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_DESCRIPTION
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_EXISTS
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_IMAGE_URL
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_LABEL_ICON
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_LABEL_TEXT
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_LANGUAGE
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_LAT
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_LONG
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_NAME
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_PIC
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_WIKIDATA_LINK
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_WIKIPEDIA_LINK
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.CREATE_TABLE_STATEMENT
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.DROP_TABLE_STATEMENT
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.onCreate
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.onDelete
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.onUpdate
import fr.free.nrw.commons.db.AppDatabase
import fr.free.nrw.commons.location.LatLng
import fr.free.nrw.commons.nearby.Label
import fr.free.nrw.commons.nearby.Place
import fr.free.nrw.commons.nearby.Sitelinks
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.verifyNoInteractions
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
@ -55,28 +41,11 @@ import org.robolectric.annotation.Config
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [21], application = TestCommonsApplication::class)
class BookMarkLocationDaoTest {
private val columns =
arrayOf(
COLUMN_NAME,
COLUMN_LANGUAGE,
COLUMN_DESCRIPTION,
COLUMN_CATEGORY,
COLUMN_LABEL_TEXT,
COLUMN_LABEL_ICON,
COLUMN_IMAGE_URL,
COLUMN_WIKIPEDIA_LINK,
COLUMN_WIKIDATA_LINK,
COLUMN_COMMONS_LINK,
COLUMN_LAT,
COLUMN_LONG,
COLUMN_PIC,
COLUMN_EXISTS,
)
private val client: ContentProviderClient = mock()
private val database: SQLiteDatabase = mock()
private val captor = argumentCaptor<ContentValues>()
private lateinit var testObject: BookmarkLocationsDao
private lateinit var bookmarkLocationsDao: BookmarkLocationsDao
private lateinit var database: AppDatabase
private lateinit var examplePlaceBookmark: Place
private lateinit var exampleLabel: Label
private lateinit var exampleUri: Uri
@ -89,10 +58,18 @@ class BookMarkLocationDaoTest {
exampleUri = Uri.parse("wikimedia/uri")
exampleLocation = LatLng(40.0, 51.4, 1f)
builder = Sitelinks.Builder()
builder.setWikipediaLink("wikipediaLink")
builder.setWikidataLink("wikidataLink")
builder.setCommonsLink("commonsLink")
database = Room.inMemoryDatabaseBuilder(
ApplicationProvider.getApplicationContext(),
AppDatabase::class.java
).allowMainThreadQueries().build()
bookmarkLocationsDao = database.bookmarkLocationsDao()
builder = Sitelinks.Builder().apply {
setWikipediaLink("wikipediaLink")
setWikidataLink("wikidataLink")
setCommonsLink("commonsLink")
}
examplePlaceBookmark =
Place(
@ -106,236 +83,75 @@ class BookMarkLocationDaoTest {
"picName",
false,
)
testObject = BookmarkLocationsDao { client }
}
@After
fun tearDown() {
database.close()
}
@Test
fun createTable() {
onCreate(database)
verify(database).execSQL(CREATE_TABLE_STATEMENT)
fun testForAddAndGetAllBookmarkLocations() = runBlocking {
bookmarkLocationsDao.addBookmarkLocation(examplePlaceBookmark.toBookmarksLocations())
val bookmarks = bookmarkLocationsDao.getAllBookmarksLocations()
assertEquals(1, bookmarks.size)
val retrievedBookmark = bookmarks.first()
assertEquals(examplePlaceBookmark.name, retrievedBookmark.locationName)
assertEquals(examplePlaceBookmark.language, retrievedBookmark.locationLanguage)
}
@Test
fun deleteTable() {
onDelete(database)
inOrder(database) {
verify(database).execSQL(DROP_TABLE_STATEMENT)
verify(database).execSQL(CREATE_TABLE_STATEMENT)
}
fun testFindBookmarkByNameForTrue() = runBlocking {
bookmarkLocationsDao.addBookmarkLocation(examplePlaceBookmark.toBookmarksLocations())
val exists = bookmarkLocationsDao.findBookmarkLocation(examplePlaceBookmark.name)
assertTrue(exists)
}
@Test
fun createFromCursor() {
createCursor(1).let { cursor ->
cursor.moveToFirst()
testObject.fromCursor(cursor).let {
assertEquals("en", it.language)
assertEquals("placeName", it.name)
assertEquals(Label.FOREST, it.label)
assertEquals("placeDescription", it.longDescription)
assertEquals(40.0, it.location.latitude, 0.001)
assertEquals(51.4, it.location.longitude, 0.001)
assertEquals("placeCategory", it.category)
assertEquals(builder.build().wikipediaLink, it.siteLinks.wikipediaLink)
assertEquals(builder.build().wikidataLink, it.siteLinks.wikidataLink)
assertEquals(builder.build().commonsLink, it.siteLinks.commonsLink)
assertEquals("picName", it.pic)
assertEquals(false, it.exists)
}
}
fun testFindBookmarkByNameForFalse() = runBlocking {
bookmarkLocationsDao.addBookmarkLocation(examplePlaceBookmark.toBookmarksLocations())
val exists = bookmarkLocationsDao.findBookmarkLocation("xyz")
assertFalse(exists)
}
@Test
fun getAllLocationBookmarks() {
whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenReturn(createCursor(14))
fun testDeleteBookmark() = runBlocking {
val bookmarkLocation = examplePlaceBookmark.toBookmarksLocations()
bookmarkLocationsDao.addBookmarkLocation(bookmarkLocation)
var result = testObject.allBookmarksLocations
bookmarkLocationsDao.deleteBookmarkLocation(bookmarkLocation)
assertEquals(14, result.size)
}
@Test(expected = RuntimeException::class)
fun getAllLocationBookmarksTranslatesExceptions() {
whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenThrow(RemoteException(""))
testObject.allBookmarksLocations
val bookmarks = bookmarkLocationsDao.getAllBookmarksLocations()
assertTrue(bookmarks.isEmpty())
}
@Test
fun getAllLocationBookmarksReturnsEmptyList_emptyCursor() {
whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenReturn(createCursor(0))
assertTrue(testObject.allBookmarksLocations.isEmpty())
fun testUpdateBookmarkForTrue() = runBlocking {
val exists = bookmarkLocationsDao.updateBookmarkLocation(examplePlaceBookmark)
assertTrue(exists)
}
@Test
fun getAllLocationBookmarksReturnsEmptyList_nullCursor() {
whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenReturn(null)
assertTrue(testObject.allBookmarksLocations.isEmpty())
fun testUpdateBookmarkForFalse() = runBlocking {
val newBookmark = examplePlaceBookmark.toBookmarksLocations()
bookmarkLocationsDao.addBookmarkLocation(newBookmark)
val exists = bookmarkLocationsDao.updateBookmarkLocation(examplePlaceBookmark)
assertFalse(exists)
}
@Test
fun cursorsAreClosedAfterGetAllLocationBookmarksQuery() {
val mockCursor: Cursor = mock()
whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenReturn(mockCursor)
whenever(mockCursor.moveToFirst()).thenReturn(false)
fun testGetAllBookmarksLocationsPlace() = runBlocking {
val bookmarkLocation = examplePlaceBookmark.toBookmarksLocations()
bookmarkLocationsDao.addBookmarkLocation(bookmarkLocation)
testObject.allBookmarksLocations
verify(mockCursor).close()
val bookmarks = bookmarkLocationsDao.getAllBookmarksLocationsPlace()
assertEquals(1, bookmarks.size)
assertEquals(examplePlaceBookmark.name, bookmarks.first().name)
}
@Test
fun updateNewLocationBookmark() {
whenever(client.insert(any(), any())).thenReturn(Uri.EMPTY)
whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(null)
assertTrue(testObject.updateBookmarkLocation(examplePlaceBookmark))
verify(client).insert(eq(BASE_URI), captor.capture())
captor.firstValue.let { cv ->
assertEquals(13, cv.size())
assertEquals(examplePlaceBookmark.name, cv.getAsString(COLUMN_NAME))
assertEquals(examplePlaceBookmark.language, cv.getAsString(COLUMN_LANGUAGE))
assertEquals(examplePlaceBookmark.longDescription, cv.getAsString(COLUMN_DESCRIPTION))
assertEquals(examplePlaceBookmark.label.text, cv.getAsString(COLUMN_LABEL_TEXT))
assertEquals(examplePlaceBookmark.category, cv.getAsString(COLUMN_CATEGORY))
assertEquals(examplePlaceBookmark.location.latitude, cv.getAsDouble(COLUMN_LAT), 0.001)
assertEquals(examplePlaceBookmark.location.longitude, cv.getAsDouble(COLUMN_LONG), 0.001)
assertEquals(examplePlaceBookmark.siteLinks.wikipediaLink.toString(), cv.getAsString(COLUMN_WIKIPEDIA_LINK))
assertEquals(examplePlaceBookmark.siteLinks.wikidataLink.toString(), cv.getAsString(COLUMN_WIKIDATA_LINK))
assertEquals(examplePlaceBookmark.siteLinks.commonsLink.toString(), cv.getAsString(COLUMN_COMMONS_LINK))
assertEquals(examplePlaceBookmark.pic, cv.getAsString(COLUMN_PIC))
assertEquals(examplePlaceBookmark.exists.toString(), cv.getAsString(COLUMN_EXISTS))
}
}
@Test
fun updateExistingLocationBookmark() {
whenever(client.delete(isA(), isNull(), isNull())).thenReturn(1)
whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(createCursor(1))
assertFalse(testObject.updateBookmarkLocation(examplePlaceBookmark))
verify(client).delete(eq(BookmarkLocationsContentProvider.uriForName(examplePlaceBookmark.name)), isNull(), isNull())
}
@Test
fun findExistingLocationBookmark() {
whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(createCursor(1))
assertTrue(testObject.findBookmarkLocation(examplePlaceBookmark))
}
@Test(expected = RuntimeException::class)
fun findLocationBookmarkTranslatesExceptions() {
whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenThrow(RemoteException(""))
testObject.findBookmarkLocation(examplePlaceBookmark)
}
@Test
fun findNotExistingLocationBookmarkReturnsNull_emptyCursor() {
whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(createCursor(0))
assertFalse(testObject.findBookmarkLocation(examplePlaceBookmark))
}
@Test
fun findNotExistingLocationBookmarkReturnsNull_nullCursor() {
whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(null)
assertFalse(testObject.findBookmarkLocation(examplePlaceBookmark))
}
@Test
fun cursorsAreClosedAfterFindLocationBookmarkQuery() {
val mockCursor: Cursor = mock()
whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenReturn(mockCursor)
whenever(mockCursor.moveToFirst()).thenReturn(false)
testObject.findBookmarkLocation(examplePlaceBookmark)
verify(mockCursor).close()
}
@Test
fun migrateTableVersionFrom_v1_to_v2() {
onUpdate(database, 1, 2)
// Table didn't exist before v5
verifyNoInteractions(database)
}
@Test
fun migrateTableVersionFrom_v2_to_v3() {
onUpdate(database, 2, 3)
// Table didn't exist before v5
verifyNoInteractions(database)
}
@Test
fun migrateTableVersionFrom_v3_to_v4() {
onUpdate(database, 3, 4)
// Table didnt exist before v5
verifyNoInteractions(database)
}
@Test
fun migrateTableVersionFrom_v4_to_v5() {
onUpdate(database, 4, 5)
// Table didnt change in version 5
verifyNoInteractions(database)
}
@Test
fun migrateTableVersionFrom_v5_to_v6() {
onUpdate(database, 5, 6)
// Table didnt change in version 6
verifyNoInteractions(database)
}
@Test
fun migrateTableVersionFrom_v6_to_v7() {
onUpdate(database, 6, 7)
// Table didnt change in version 7
verifyNoInteractions(database)
}
@Test
fun migrateTableVersionFrom_v7_to_v8() {
onUpdate(database, 7, 8)
verify(database).execSQL(CREATE_TABLE_STATEMENT)
}
@Test
fun migrateTableVersionFrom_v12_to_v13() {
onUpdate(database, 12, 13)
verify(database).execSQL("ALTER TABLE bookmarksLocations ADD COLUMN location_destroyed STRING;")
}
@Test
fun migrateTableVersionFrom_v13_to_v14() {
onUpdate(database, 13, 14)
verify(database).execSQL("ALTER TABLE bookmarksLocations ADD COLUMN location_language STRING;")
}
@Test
fun migrateTableVersionFrom_v14_to_v15() {
onUpdate(database, 14, 15)
verify(database).execSQL("ALTER TABLE bookmarksLocations ADD COLUMN location_exists STRING;")
}
private fun createCursor(rows: Int): Cursor =
MatrixCursor(columns, rows).apply {
repeat(rows) {
newRow().apply {
add("placeName")
add("en")
add("placeDescription")
add("placeCategory")
add(Label.FOREST.text)
add(Label.FOREST.icon)
add("placeImage")
add("wikipediaLink")
add("wikidataLink")
add("commonsLink")
add(40.0)
add(51.4)
add("picName")
add(false)
}
}
}
}

View file

@ -2,6 +2,7 @@ package fr.free.nrw.commons.bookmarks.locations
import com.nhaarman.mockitokotlin2.whenever
import fr.free.nrw.commons.nearby.Place
import kotlinx.coroutines.runBlocking
import org.junit.Assert
import org.junit.Before
import org.junit.Test
@ -19,9 +20,11 @@ class BookmarkLocationControllerTest {
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
whenever(bookmarkDao!!.allBookmarksLocations)
.thenReturn(mockBookmarkList)
MockitoAnnotations.openMocks(this)
runBlocking {
whenever(bookmarkDao!!.getAllBookmarksLocationsPlace())
.thenReturn(mockBookmarkList)
}
}
/**
@ -66,7 +69,7 @@ class BookmarkLocationControllerTest {
* Test case where all bookmark locations are fetched and media is found against it
*/
@Test
fun loadBookmarkedLocations() {
fun loadBookmarkedLocations() = runBlocking {
val bookmarkedLocations =
bookmarkLocationsController.loadFavoritesLocations()
Assert.assertEquals(2, bookmarkedLocations.size.toLong())

View file

@ -10,6 +10,7 @@ import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentTransaction
import androidx.recyclerview.widget.RecyclerView
import androidx.test.core.app.ApplicationProvider
import com.nhaarman.mockitokotlin2.verify
import com.nhaarman.mockitokotlin2.whenever
import fr.free.nrw.commons.OkHttpConnectionFactory
import fr.free.nrw.commons.R
@ -22,11 +23,14 @@ import fr.free.nrw.commons.nearby.Place
import fr.free.nrw.commons.nearby.fragments.CommonPlaceClickActions
import fr.free.nrw.commons.nearby.fragments.PlaceAdapter
import fr.free.nrw.commons.profile.ProfileActivity
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import org.junit.Assert
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.spy
import org.mockito.MockitoAnnotations
import org.powermock.reflect.Whitebox
import org.robolectric.Robolectric
@ -129,11 +133,13 @@ class BookmarkLocationFragmentUnitTests {
*/
@Test
fun testInitNonEmpty() {
whenever(controller.loadFavoritesLocations()).thenReturn(mockBookmarkList)
val method: Method =
BookmarkLocationsFragment::class.java.getDeclaredMethod("initList")
method.isAccessible = true
method.invoke(fragment)
runBlocking {
whenever(controller.loadFavoritesLocations()).thenReturn(mockBookmarkList)
val method: Method =
BookmarkLocationsFragment::class.java.getDeclaredMethod("initList")
method.isAccessible = true
method.invoke(fragment)
}
}
/**
@ -168,7 +174,11 @@ class BookmarkLocationFragmentUnitTests {
*/
@Test
@Throws(Exception::class)
fun testOnResume() {
fragment.onResume()
fun testOnResume() = runBlocking {
val fragmentSpy = spy(fragment)
whenever(controller.loadFavoritesLocations()).thenReturn(mockBookmarkList)
fragmentSpy.onResume()
verify(fragmentSpy).initList()
}
}

View file

@ -8,6 +8,7 @@ import fr.free.nrw.commons.location.LatLng
import fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType
import fr.free.nrw.commons.nearby.contract.NearbyParentFragmentContract
import fr.free.nrw.commons.nearby.presenter.NearbyParentFragmentPresenter
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
@ -463,7 +464,9 @@ class NearbyParentFragmentPresenterTest {
nearbyPlacesInfo.searchLatLng = latestLocation
nearbyPlacesInfo.placeList = emptyList<Place>()
whenever(bookmarkLocationsDao.allBookmarksLocations).thenReturn(Collections.emptyList())
runBlocking {
whenever(bookmarkLocationsDao.getAllBookmarksLocations()).thenReturn(Collections.emptyList())
}
nearbyPresenter.updateMapMarkers(nearbyPlacesInfo.placeList, latestLocation, null)
Mockito.verify(nearbyParentFragmentView).setProgressBarVisibility(false)
}