Fixed 4616 : Option for editing depictions (#4725)

* Dialog can't be dismissed

* Dialog can't be dismissed

* Option for editing depiction

* Java docs added

* Minor issues fixed

* Lining done

* "Depictions not updating instantly" issue resolved

* Existing Depicts on the top

* Existing Depicts on the top

* Back press handled

* Previous depictions unchecked

* Whole Screen issue fixed

* Nearby banner removed

* Test fixed

* Upload Wizard issue fixed

* Upload Wizard issue fixed

* Previous depicts issue fixed

* Previous depicts issue fixed

* All issues fixed

* Fixed late loading of updated depicts

* Depiction is removable

* Test fixed

* Back button press handled after losing focus for edittext

* RequiresApi removed

* RequiresApi removed

* Test fixed

* Requested changes

* Test added

* Test added

* UploadModelUnitTest added

* DepictEditHelperUnitTest added

* DepictEditHelperUnitTest added

* Test added

* More test added

* Indentation Reversed

* Indentation reversed

* Update MediaDetailFragment.java

* Indentation reversed

* Update MediaDetailFragment.java

* Indentation reversed

* Indentation reversed

* Indentation reversed

* Indentation reversed

* More test added

* More test added

* Minor fixes

* Minor fixes

* Minor fixes
This commit is contained in:
Ayan Sarkar 2022-03-22 11:03:43 +05:30 committed by GitHub
parent e58322ed63
commit bd9531b969
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 1261 additions and 75 deletions

View file

@ -9,6 +9,7 @@ import android.os.Bundle
import android.os.Looper
import android.view.LayoutInflater
import android.view.View
import android.view.View.GONE
import android.view.ViewTreeObserver
import android.webkit.WebView
import android.widget.*
@ -19,7 +20,6 @@ import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.drawee.generic.GenericDraweeHierarchy
import com.facebook.drawee.view.SimpleDraweeView
import com.facebook.soloader.SoLoader
import fr.free.nrw.commons.*
import fr.free.nrw.commons.LocationPicker.LocationPickerActivity
import org.robolectric.Shadows.shadowOf
import fr.free.nrw.commons.category.CategoryEditSearchRecyclerViewAdapter
@ -34,10 +34,8 @@ import fr.free.nrw.commons.TestCommonsApplication
import fr.free.nrw.commons.R
import fr.free.nrw.commons.TestAppAdapter
import fr.free.nrw.commons.Media
import fr.free.nrw.commons.contributions.ContributionViewHolder
import fr.free.nrw.commons.delete.DeleteHelper
import fr.free.nrw.commons.delete.ReasonBuilder
import fr.free.nrw.commons.utils.ImageUtils
import io.reactivex.Single
import org.junit.Test
import org.junit.runner.RunWith
@ -218,6 +216,7 @@ class MediaDetailFragmentUnitTests {
Whitebox.setInternalState(fragment, "showCaptionAndDescriptionContainer", linearLayout)
Whitebox.setInternalState(fragment, "updateCategoriesButton", button)
Whitebox.setInternalState(fragment, "editDescription", button)
Whitebox.setInternalState(fragment, "depictEditButton", button)
Whitebox.setInternalState(fragment, "categoryContainer", linearLayout)
Whitebox.setInternalState(fragment, "categorySearchView", searchView)
Whitebox.setInternalState(fragment, "progressBarDeletion", progressBarDeletion)
@ -656,4 +655,17 @@ class MediaDetailFragmentUnitTests {
MediaDetailFragment.forMedia(0, true, true, true)
}
@Test
@Throws(Exception::class)
fun testOnDepictEditButtonClicked() {
fragment.onDepictionsEditButtonClicked()
verify(linearLayout).removeAllViews()
verify(button).visibility = GONE
}
@Test
@Throws(Exception::class)
fun testOnDeleteButtonClicked() {
fragment.onDeleteButtonClicked()
}
}

View file

@ -1,10 +1,11 @@
package fr.free.nrw.commons.upload
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.jraska.livedata.test
import com.nhaarman.mockitokotlin2.times
import com.nhaarman.mockitokotlin2.verify
import com.nhaarman.mockitokotlin2.whenever
import depictedItem
import fr.free.nrw.commons.Media
import fr.free.nrw.commons.explore.depictions.DepictsClient
import fr.free.nrw.commons.repository.UploadRepository
import fr.free.nrw.commons.upload.depicts.DepictsContract
@ -16,7 +17,10 @@ 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.powermock.reflect.Whitebox
import java.lang.reflect.Method
class DepictsPresenterTest {
@ -37,6 +41,9 @@ class DepictsPresenterTest {
@Mock
lateinit var depictsClient: DepictsClient
@Mock
private lateinit var media: Media
/**
* initial setup
*/
@ -92,9 +99,6 @@ class DepictsPresenterTest {
testScheduler.triggerActions()
verify(view).showProgress(false)
verify(view).showError(true)
depictsPresenter.depictedItems
.test()
.assertValue(emptyList())
}
@Test
@ -116,7 +120,7 @@ class DepictsPresenterTest {
fun `onDepictItemClicked calls repository`() {
val depictedItem = depictedItem()
depictsPresenter.onDepictItemClicked(depictedItem)
verify(repository).onDepictItemClicked(depictedItem)
verify(repository).onDepictItemClicked(depictedItem, null)
}
@Test
@ -132,4 +136,63 @@ class DepictsPresenterTest {
depictsPresenter.verifyDepictions()
verify(view).noDepictionSelected()
}
@Test
fun testOnAttachViewWithMedia() {
depictsPresenter.onAttachViewWithMedia(view, Mockito.mock(Media::class.java))
}
@Test
fun testUpdateDepicts() {
depictsPresenter.updateDepictions(Mockito.mock(Media::class.java))
}
@Test
fun `Test searchResults when media is null`() {
whenever(repository.searchAllEntities("querystring"))
.thenReturn(Flowable.just(listOf(depictedItem())))
val method: Method = DepictsPresenter::class.java.getDeclaredMethod(
"searchResults",
String::class.java
)
method.isAccessible = true
method.invoke(depictsPresenter, "querystring")
verify(repository, times(1)).searchAllEntities("querystring")
}
@Test
fun `Test searchResults when media is not null`() {
Whitebox.setInternalState(depictsPresenter, "media", media)
whenever(repository.getDepictions(repository.selectedExistingDepictions))
.thenReturn(Flowable.just(listOf(depictedItem())))
whenever(repository.searchAllEntities("querystring"))
.thenReturn(Flowable.just(listOf(depictedItem())))
val method: Method = DepictsPresenter::class.java.getDeclaredMethod(
"searchResults",
String::class.java
)
method.isAccessible = true
method.invoke(depictsPresenter, "querystring")
verify(repository, times(1)).searchAllEntities("querystring")
}
@Test
fun testSelectNewDepictions() {
Whitebox.setInternalState(depictsPresenter, "media", media)
val method: Method = DepictsPresenter::class.java.getDeclaredMethod(
"selectNewDepictions",
List::class.java
)
method.isAccessible = true
method.invoke(depictsPresenter, listOf(depictedItem()))
}
@Test
fun testClearPreviousSelection() {
val method: Method = DepictsPresenter::class.java.getDeclaredMethod(
"clearPreviousSelection"
)
method.isAccessible = true
method.invoke(depictsPresenter)
}
}

View file

@ -0,0 +1,126 @@
package fr.free.nrw.commons.upload
import android.content.Context
import fr.free.nrw.commons.auth.SessionManager
import fr.free.nrw.commons.kvstore.JsonKvStore
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem
import media
import org.junit.Before
import org.junit.Test
import org.mockito.Mockito.mock
import org.mockito.MockitoAnnotations
class UploadModelUnitTest {
private lateinit var uploadModel: UploadModel
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
uploadModel = UploadModel(
listOf(),
mock(JsonKvStore::class.java),
mapOf(),
mock(Context::class.java),
mock(SessionManager::class.java),
mock(FileProcessor::class.java),
mock(ImageProcessingService::class.java)
)
}
@Test
fun `Test onDepictItemClicked when DepictedItem is selected`(){
uploadModel.onDepictItemClicked(
DepictedItem(
"Test",
"Test",
"test",
listOf(),
listOf(),
true,
"depictionId"
), media(filename = "File:Example.jpg"))
}
@Test
fun `Test onDepictItemClicked when DepictedItem is not selected`(){
uploadModel.onDepictItemClicked(
DepictedItem(
"Test",
"Test",
"test",
listOf(),
listOf(),
false,
"depictionId"
), media(filename = "File:Example.jpg")
)
}
@Test
fun `Test onDepictItemClicked when DepictedItem is not selected and not included in media`(){
uploadModel.onDepictItemClicked(
DepictedItem(
"Test",
"Test",
"test",
listOf(),
listOf(),
false,
"id"
), media(filename = "File:Example.jpg")
)
}
@Test
fun `Test onDepictItemClicked when media is null and DepictedItem is not selected`(){
uploadModel.onDepictItemClicked(
DepictedItem(
"Test",
"Test",
"test",
listOf(),
listOf(),
false,
"id"
), null)
}
@Test
fun `Test onDepictItemClicked when media is not null and DepictedItem is selected`(){
uploadModel.onDepictItemClicked(
DepictedItem(
"Test",
"Test",
"test",
listOf(),
listOf(),
true,
"id"
), media(filename = "File:Example.jpg"))
}
@Test
fun `Test onDepictItemClicked when media is null and DepictedItem is selected`(){
uploadModel.onDepictItemClicked(
DepictedItem(
"Test",
"Test",
"test",
listOf(),
listOf(),
true,
"id"
), null)
}
@Test
fun testGetSelectedExistingDepictions(){
uploadModel.selectedExistingDepictions
}
@Test
fun testSetSelectedExistingDepictions(){
uploadModel.selectedExistingDepictions = listOf("")
}
}

View file

@ -1,5 +1,6 @@
package fr.free.nrw.commons.upload
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.verify
import fr.free.nrw.commons.category.CategoriesModel
import fr.free.nrw.commons.category.CategoryItem
@ -13,12 +14,15 @@ import fr.free.nrw.commons.repository.UploadRepository
import fr.free.nrw.commons.upload.structure.depictions.DepictModel
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem
import io.reactivex.Completable
import io.reactivex.Single
import org.junit.Before
import org.junit.Test
import org.junit.jupiter.api.Assertions.assertEquals
import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.mockito.Mockito.mock
import org.mockito.MockitoAnnotations
import java.lang.reflect.Method
class UploadRepositoryUnitTest {
@ -204,11 +208,17 @@ class UploadRepositoryUnitTest {
assertEquals(repository.setSelectedLicense(""), uploadModel.setSelectedLicense(""))
}
@Test
fun testSetSelectedExistingDepictions() {
assertEquals(repository.setSelectedExistingDepictions(listOf("")),
uploadModel.setSelectedExistingDepictions(listOf("")))
}
@Test
fun testOnDepictItemClicked() {
assertEquals(
repository.onDepictItemClicked(depictedItem),
uploadModel.onDepictItemClicked(depictedItem)
repository.onDepictItemClicked(depictedItem, mock()),
uploadModel.onDepictItemClicked(depictedItem, mock())
)
}
@ -217,6 +227,11 @@ class UploadRepositoryUnitTest {
assertEquals(repository.selectedDepictions, uploadModel.selectedDepictions)
}
@Test
fun testGetSelectedExistingDepictions() {
assertEquals(repository.selectedExistingDepictions, uploadModel.selectedExistingDepictions)
}
@Test
fun testSearchAllEntities() {
assertEquals(
@ -292,4 +307,36 @@ class UploadRepositoryUnitTest {
)
}
@Test
fun testGetDepictions() {
`when`(depictModel.getDepictions("Q12"))
.thenReturn(Single.just(listOf(mock(DepictedItem::class.java))))
val method: Method = UploadRepository::class.java.getDeclaredMethod(
"getDepictions",
List::class.java
)
method.isAccessible = true
method.invoke(repository, listOf("Q12"))
}
@Test
fun testJoinIDs() {
val method: Method = UploadRepository::class.java.getDeclaredMethod(
"joinQIDs",
List::class.java
)
method.isAccessible = true
method.invoke(repository, listOf("Q12", "Q23"))
}
@Test
fun `test joinIDs when depictIDs is null`() {
val method: Method = UploadRepository::class.java.getDeclaredMethod(
"joinQIDs",
List::class.java
)
method.isAccessible = true
method.invoke(repository, null)
}
}

View file

@ -0,0 +1,109 @@
package fr.free.nrw.commons.upload.depicts
import android.content.Context
import com.nhaarman.mockitokotlin2.whenever
import fr.free.nrw.commons.Media
import fr.free.nrw.commons.R
import fr.free.nrw.commons.TestCommonsApplication
import fr.free.nrw.commons.notification.NotificationHelper
import fr.free.nrw.commons.utils.ViewUtilWrapper
import fr.free.nrw.commons.wikidata.WikidataEditService
import io.reactivex.Observable
import org.junit.Assert
import org.junit.Before
import org.junit.Test
import org.junit.jupiter.api.Assertions
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.MockitoAnnotations
import org.powermock.reflect.Whitebox
import org.robolectric.RobolectricTestRunner
import org.robolectric.RuntimeEnvironment
import org.robolectric.annotation.Config
import org.robolectric.annotation.LooperMode
import java.lang.reflect.Method
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [21], application = TestCommonsApplication::class)
@LooperMode(LooperMode.Mode.PAUSED)
class DepictEditHelperUnitTest {
private lateinit var context: Context
private lateinit var helper: DepictEditHelper
@Mock
private lateinit var notificationHelper: NotificationHelper
@Mock
private lateinit var wikidataEditService: WikidataEditService
@Mock
private lateinit var viewUtilWrapper: ViewUtilWrapper
@Mock
private lateinit var media: Media
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
context = RuntimeEnvironment.application.applicationContext
helper = DepictEditHelper(notificationHelper, wikidataEditService, viewUtilWrapper)
Whitebox.setInternalState(helper, "viewUtilWrapper", viewUtilWrapper)
Whitebox.setInternalState(helper, "notificationHelper", notificationHelper)
Whitebox.setInternalState(helper, "wikidataEditService", wikidataEditService)
}
@Test
@Throws(Exception::class)
fun checkNotNull() {
Assert.assertNotNull(helper)
}
@Test
@Throws(Exception::class)
fun testMakeDepictEdit() {
whenever(wikidataEditService.updateDepictsProperty(media.filename, listOf("Q12")))
.thenReturn(Observable.just(true))
helper.makeDepictionEdit(context, media, listOf("Q12"))
Mockito.verify(viewUtilWrapper, Mockito.times(1)).showShortToast(
context,
context.getString(R.string.depictions_edit_helper_make_edit_toast)
)
}
@Test
@Throws(Exception::class)
fun testShowCoordinatesEditNotificationCaseTrue() {
whenever(media.depictionIds).thenReturn(listOf("id", "id2"))
val method: Method = DepictEditHelper::class.java.getDeclaredMethod(
"showDepictionEditNotification",
Context::class.java,
Media::class.java,
Boolean::class.java
)
method.isAccessible = true
Assertions.assertEquals(
method.invoke(helper, context, media, true),
true
)
}
@Test
@Throws(Exception::class)
fun testShowCoordinatesEditNotificationCaseFalse() {
val method: Method = DepictEditHelper::class.java.getDeclaredMethod(
"showDepictionEditNotification",
Context::class.java,
Media::class.java,
Boolean::class.java
)
method.isAccessible = true
Assertions.assertEquals(
method.invoke(helper, context, media, false),
false
)
}
}

View file

@ -1,9 +1,11 @@
package fr.free.nrw.commons.upload.depicts
import android.app.ProgressDialog
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.widget.Button
import android.widget.ImageView
import android.widget.ProgressBar
import android.widget.TextView
@ -11,9 +13,13 @@ import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentTransaction
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.textfield.TextInputLayout
import com.nhaarman.mockitokotlin2.whenever
import depictedItem
import fr.free.nrw.commons.Media
import fr.free.nrw.commons.R
import fr.free.nrw.commons.TestAppAdapter
import fr.free.nrw.commons.TestCommonsApplication
import fr.free.nrw.commons.kvstore.JsonKvStore
import fr.free.nrw.commons.ui.PasteSensitiveTextInputEditText
import fr.free.nrw.commons.upload.UploadActivity
import fr.free.nrw.commons.upload.UploadBaseFragment
@ -62,6 +68,9 @@ class DepictsFragmentUnitTests {
@Mock
private lateinit var progressBar: ProgressBar
@Mock
private lateinit var button: Button
@Mock
private lateinit var textInputLayout: TextInputLayout
@ -74,6 +83,15 @@ class DepictsFragmentUnitTests {
@Mock
private lateinit var adapter: UploadDepictsAdapter
@Mock
private lateinit var applicationKvStore: JsonKvStore
@Mock
private lateinit var media: Media
@Mock
private lateinit var progressDialog: ProgressDialog
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
@ -95,6 +113,8 @@ class DepictsFragmentUnitTests {
Whitebox.setInternalState(fragment, "depictsTitle", textView)
Whitebox.setInternalState(fragment, "callback", callback)
Whitebox.setInternalState(fragment, "tooltip", imageView)
Whitebox.setInternalState(fragment, "btnNext", button)
Whitebox.setInternalState(fragment, "btnPrevious", button)
Whitebox.setInternalState(fragment, "depictsSubTitle", textView)
Whitebox.setInternalState(fragment, "depictsRecyclerView", recyclerView)
Whitebox.setInternalState(fragment, "depictsSearch", textInputEditText)
@ -126,6 +146,17 @@ class DepictsFragmentUnitTests {
method.invoke(fragment)
}
@Test
@Throws(Exception::class)
fun `Test init when media is not null`() {
Whitebox.setInternalState(fragment, "media", media)
val method: Method = DepictsFragment::class.java.getDeclaredMethod(
"init"
)
method.isAccessible = true
method.invoke(fragment)
}
@Test
@Throws(Exception::class)
fun testOnBecameVisible() {
@ -184,6 +215,20 @@ class DepictsFragmentUnitTests {
fragment.setDepictsList(listOf())
}
@Test
@Throws(Exception::class)
fun `Test setDepictsList when list is not empty`() {
fragment.setDepictsList(listOf(depictedItem()))
}
@Test
@Throws(Exception::class)
fun `Test setDepictsList when applicationKvStore returns true`() {
Whitebox.setInternalState(fragment, "applicationKvStore", applicationKvStore)
whenever(applicationKvStore.getBoolean("first_edit_depict")).thenReturn(true)
fragment.setDepictsList(listOf(depictedItem()))
}
@Test
@Throws(Exception::class)
fun testOnNextButtonClicked() {
@ -207,4 +252,61 @@ class DepictsFragmentUnitTests {
method.invoke(fragment, "")
}
@Test
@Throws(Exception::class)
fun testOnResume() {
fragment.onResume()
}
@Test
@Throws(Exception::class)
fun testOnStop() {
fragment.onStop()
}
@Test
@Throws(Exception::class)
fun testInitRecyclerView() {
val method: Method = DepictsFragment::class.java.getDeclaredMethod(
"initRecyclerView"
)
method.isAccessible = true
method.invoke(fragment)
}
@Test
@Throws(Exception::class)
fun `Test initRecyclerView when media is not null`() {
Whitebox.setInternalState(fragment, "media", media)
val method: Method = DepictsFragment::class.java.getDeclaredMethod(
"initRecyclerView"
)
method.isAccessible = true
method.invoke(fragment)
}
@Test
@Throws(Exception::class)
fun testGetFragmentContext() {
fragment.fragmentContext
}
@Test
@Throws(Exception::class)
fun testGoBackToPreviousScreen() {
fragment.goBackToPreviousScreen()
}
@Test
@Throws(Exception::class)
fun testShowProgressDialog() {
fragment.showProgressDialog()
}
@Test
@Throws(Exception::class)
fun testDismissProgressDialog() {
Whitebox.setInternalState(fragment, "progressDialog", progressDialog)
fragment.dismissProgressDialog()
}
}

View file

@ -0,0 +1,31 @@
package fr.free.nrw.commons.wikidata
import org.junit.Before
import org.junit.Test
import org.mockito.InjectMocks
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.MockitoAnnotations
import org.wikipedia.csrf.CsrfTokenClient
class WikiBaseClientUnitTest {
@Mock
internal var csrfTokenClient: CsrfTokenClient? = null
@InjectMocks
var wikiBaseClient: WikiBaseClient? = null
@Before
@Throws(Exception::class)
fun setUp() {
MockitoAnnotations.initMocks(this)
Mockito.`when`(csrfTokenClient!!.tokenBlocking)
.thenReturn("test")
}
@Test
fun testPostEditEntityByFilename() {
wikiBaseClient?.postEditEntityByFilename("File:Example.jpg", "data")
}
}

View file

@ -15,7 +15,9 @@ import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyString
import org.mockito.InjectMocks
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.MockitoAnnotations
import org.wikipedia.wikidata.EditClaim
class WikidataEditServiceTest {
@Mock
@ -48,6 +50,13 @@ class WikidataEditServiceTest {
verifyZeroInteractions(wikidataClient)
}
@Test
fun testUpdateDepictsProperty() {
whenever(wikibaseClient.postEditEntityByFilename("Test.jpg",
gson.toJson(Mockito.mock(EditClaim::class.java)))).thenReturn(Observable.just(true))
wikidataEditService.updateDepictsProperty("Test.jpg", listOf())
}
@Test
fun createImageClaim() {
whenever(directKvStore.getBoolean("Picture_Has_Correct_Location", true))