mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-27 21:03:54 +01:00
Add module for file picker for camera and gallery uploads (#2375)
* Use easy image for image picker * Do not use harcoded mime type * Use uploadable file for image uploads * Add picker files in filepicker module * Remove redundant checks for file * Make usage of file extensions consistent * Add javadocs * Fix tests * Enable image upload using bookmark activity * Fix multiple uploads * Fix external image uploads * Fix chooser intents * Fix image quality checks * Segregate internal and external upload intents * Invoke all error messages from one place * Minor changes * Fix tests * Add image processing service tests
This commit is contained in:
parent
fb5a40bba5
commit
52ab39381e
39 changed files with 1553 additions and 574 deletions
|
|
@ -176,7 +176,7 @@ class ContributionDaoTest {
|
|||
@Test
|
||||
fun saveNewContribution_nullableImageUrlUsesFileAsBackup() {
|
||||
whenever(client.insert(isA(), isA())).thenReturn(contentUri)
|
||||
val contribution = createContribution(true, null, null, null, "file")
|
||||
val contribution = createContribution(true, null, null, null, "filePath")
|
||||
|
||||
testObject.save(contribution)
|
||||
|
||||
|
|
@ -186,7 +186,7 @@ class ContributionDaoTest {
|
|||
// Nullable fields are absent if null
|
||||
assertFalse(it.containsKey(Table.COLUMN_LOCAL_URI))
|
||||
assertFalse(it.containsKey(Table.COLUMN_UPLOADED))
|
||||
assertEquals(Utils.makeThumbBaseUrl("file"), it.getAsString(Table.COLUMN_IMAGE_URL))
|
||||
assertEquals(Utils.makeThumbBaseUrl("filePath"), it.getAsString(Table.COLUMN_IMAGE_URL))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -285,7 +285,7 @@ class ContributionDaoTest {
|
|||
createCursor(created, uploaded, false, localUri).let { mc ->
|
||||
testObject.fromCursor(mc).let {
|
||||
assertEquals(uriForId(111), it.contentUri)
|
||||
assertEquals("file", it.filename)
|
||||
assertEquals("filePath", it.filename)
|
||||
assertEquals(localUri, it.localUri.toString())
|
||||
assertEquals("image", it.imageUrl)
|
||||
assertEquals(created, it.dateCreated.time)
|
||||
|
|
@ -335,7 +335,7 @@ class ContributionDaoTest {
|
|||
|
||||
private fun createCursor(created: Long, uploaded: Long, multiple: Boolean, localUri: String) =
|
||||
MatrixCursor(Table.ALL_FIELDS, 1).apply {
|
||||
addRow(listOf("111", "file", localUri, "image",
|
||||
addRow(listOf("111", "filePath", localUri, "image",
|
||||
created, STATE_QUEUED, 222L, uploaded, 88L, SOURCE_GALLERY, "desc",
|
||||
"create", if (multiple) 1 else 0, 640, 480, "007", "Q1"))
|
||||
moveToFirst()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,137 @@
|
|||
package fr.free.nrw.commons.upload
|
||||
|
||||
import android.graphics.BitmapRegionDecoder
|
||||
import android.net.Uri
|
||||
import fr.free.nrw.commons.location.LatLng
|
||||
import fr.free.nrw.commons.mwapi.MediaWikiApi
|
||||
import fr.free.nrw.commons.nearby.Place
|
||||
import fr.free.nrw.commons.utils.BitmapRegionDecoderWrapper
|
||||
import fr.free.nrw.commons.utils.ImageUtils
|
||||
import fr.free.nrw.commons.utils.ImageUtilsWrapper
|
||||
import io.reactivex.Single
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.ArgumentMatchers
|
||||
import org.mockito.InjectMocks
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.*
|
||||
import org.mockito.MockitoAnnotations
|
||||
import java.io.FileInputStream
|
||||
|
||||
class ImageProcessingServiceTest {
|
||||
@Mock
|
||||
internal var fileUtilsWrapper: FileUtilsWrapper? = null
|
||||
@Mock
|
||||
internal var bitmapRegionDecoderWrapper: BitmapRegionDecoderWrapper? = null
|
||||
@Mock
|
||||
internal var imageUtilsWrapper: ImageUtilsWrapper? = null
|
||||
@Mock
|
||||
internal var mwApi: MediaWikiApi? = null
|
||||
|
||||
@InjectMocks
|
||||
var imageProcessingService: ImageProcessingService? = null
|
||||
|
||||
@Mock
|
||||
internal lateinit var uploadItem: UploadModel.UploadItem
|
||||
|
||||
@Before
|
||||
@Throws(Exception::class)
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
val mediaUri = mock(Uri::class.java)
|
||||
val mockPlace = mock(Place::class.java)
|
||||
val mockTitle = mock(Title::class.java)
|
||||
|
||||
`when`(mockPlace.wikiDataEntityId).thenReturn("Q1")
|
||||
`when`(mockPlace.getLocation()).thenReturn(mock(LatLng::class.java))
|
||||
`when`(mediaUri.path).thenReturn("filePath")
|
||||
`when`(mockTitle.isEmpty).thenReturn(false)
|
||||
`when`(mockTitle.isSet).thenReturn(true)
|
||||
|
||||
`when`(uploadItem.mediaUri).thenReturn(mediaUri)
|
||||
`when`(uploadItem.imageQuality).thenReturn(ImageUtils.IMAGE_WAIT)
|
||||
|
||||
`when`(uploadItem.title).thenReturn(mockTitle)
|
||||
|
||||
`when`(uploadItem.place).thenReturn(mockPlace)
|
||||
|
||||
`when`(fileUtilsWrapper!!.getFileInputStream(ArgumentMatchers.anyString()))
|
||||
.thenReturn(mock(FileInputStream::class.java))
|
||||
`when`(fileUtilsWrapper!!.getSHA1(any(FileInputStream::class.java)))
|
||||
.thenReturn("fileSha")
|
||||
|
||||
`when`(fileUtilsWrapper!!.getGeolocationOfFile(ArgumentMatchers.anyString()))
|
||||
.thenReturn("latLng")
|
||||
|
||||
`when`(bitmapRegionDecoderWrapper!!.newInstance(any(FileInputStream::class.java), anyBoolean()))
|
||||
.thenReturn(mock(BitmapRegionDecoder::class.java))
|
||||
`when`(imageUtilsWrapper!!.checkIfImageIsTooDark(any(BitmapRegionDecoder::class.java)))
|
||||
.thenReturn(Single.just(ImageUtils.IMAGE_OK))
|
||||
|
||||
`when`(imageUtilsWrapper!!.checkImageGeolocationIsDifferent(ArgumentMatchers.anyString(), any(LatLng::class.java)))
|
||||
.thenReturn(Single.just(ImageUtils.IMAGE_OK))
|
||||
|
||||
`when`(fileUtilsWrapper!!.getFileInputStream(ArgumentMatchers.anyString()))
|
||||
.thenReturn(mock(FileInputStream::class.java))
|
||||
`when`(fileUtilsWrapper!!.getSHA1(any(FileInputStream::class.java)))
|
||||
.thenReturn("fileSha")
|
||||
`when`(mwApi!!.existingFile(ArgumentMatchers.anyString()))
|
||||
.thenReturn(false)
|
||||
`when`(mwApi!!.fileExistsWithName(ArgumentMatchers.anyString()))
|
||||
.thenReturn(false)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun validateImageForKeepImage() {
|
||||
`when`(uploadItem.imageQuality).thenReturn(ImageUtils.IMAGE_KEEP)
|
||||
val validateImage = imageProcessingService!!.validateImage(uploadItem, false)
|
||||
assertEquals(ImageUtils.IMAGE_OK, validateImage.blockingGet())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun validateImageForDuplicateImage() {
|
||||
`when`(mwApi!!.existingFile(ArgumentMatchers.anyString()))
|
||||
.thenReturn(true)
|
||||
val validateImage = imageProcessingService!!.validateImage(uploadItem, false)
|
||||
assertEquals(ImageUtils.IMAGE_DUPLICATE, validateImage.blockingGet())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun validateImageForOkImage() {
|
||||
val validateImage = imageProcessingService!!.validateImage(uploadItem, false)
|
||||
assertEquals(ImageUtils.IMAGE_OK, validateImage.blockingGet())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun validateImageForDarkImage() {
|
||||
`when`(imageUtilsWrapper!!.checkIfImageIsTooDark(any(BitmapRegionDecoder::class.java)))
|
||||
.thenReturn(Single.just(ImageUtils.IMAGE_DARK))
|
||||
val validateImage = imageProcessingService!!.validateImage(uploadItem, false)
|
||||
assertEquals(ImageUtils.IMAGE_DARK, validateImage.blockingGet())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun validateImageForWrongGeoLocation() {
|
||||
`when`(imageUtilsWrapper!!.checkImageGeolocationIsDifferent(ArgumentMatchers.anyString(), any(LatLng::class.java)))
|
||||
.thenReturn(Single.just(ImageUtils.IMAGE_GEOLOCATION_DIFFERENT))
|
||||
val validateImage = imageProcessingService!!.validateImage(uploadItem, false)
|
||||
assertEquals(ImageUtils.IMAGE_GEOLOCATION_DIFFERENT, validateImage.blockingGet())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun validateImageForFileNameExistsWithCheckTitleOff() {
|
||||
`when`(mwApi!!.fileExistsWithName(ArgumentMatchers.anyString()))
|
||||
.thenReturn(true)
|
||||
val validateImage = imageProcessingService!!.validateImage(uploadItem, false)
|
||||
assertEquals(ImageUtils.IMAGE_OK, validateImage.blockingGet())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun validateImageForFileNameExistsWithCheckTitleOn() {
|
||||
`when`(mwApi!!.fileExistsWithName(ArgumentMatchers.nullable(String::class.java)))
|
||||
.thenReturn(true)
|
||||
val validateImage = imageProcessingService!!.validateImage(uploadItem, true)
|
||||
assertEquals(ImageUtils.FILE_NAME_EXISTS, validateImage.blockingGet())
|
||||
}
|
||||
}
|
||||
|
|
@ -2,8 +2,8 @@ package fr.free.nrw.commons.upload
|
|||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import fr.free.nrw.commons.auth.SessionManager
|
||||
import fr.free.nrw.commons.contributions.UploadableFile
|
||||
import fr.free.nrw.commons.kvstore.BasicKvStore
|
||||
import fr.free.nrw.commons.mwapi.MediaWikiApi
|
||||
import fr.free.nrw.commons.nearby.Place
|
||||
|
|
@ -14,8 +14,7 @@ import org.junit.Assert.assertFalse
|
|||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.ArgumentMatchers.any
|
||||
import org.mockito.ArgumentMatchers.anyString
|
||||
import org.mockito.ArgumentMatchers.*
|
||||
import org.mockito.InjectMocks
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.`when`
|
||||
|
|
@ -70,10 +69,8 @@ class UploadModelTest {
|
|||
.thenReturn(mock(FileInputStream::class.java))
|
||||
`when`(fileUtilsWrapper!!.getGeolocationOfFile(anyString()))
|
||||
.thenReturn("")
|
||||
`when`(imageProcessingService!!.checkImageQuality(anyString()))
|
||||
.thenReturn(Single.just(IMAGE_OK))
|
||||
`when`(imageProcessingService!!.checkImageQuality(any(Place::class.java), anyString()))
|
||||
.thenReturn(Single.just(IMAGE_OK))
|
||||
`when`(imageProcessingService!!.validateImage(any(UploadModel.UploadItem::class.java), anyBoolean()))
|
||||
.thenReturn(Single.just(IMAGE_OK));
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -84,10 +81,7 @@ class UploadModelTest {
|
|||
|
||||
@Test
|
||||
fun receive() {
|
||||
val element = getElement()
|
||||
val element2 = getElement()
|
||||
var uriList: List<Uri> = mutableListOf<Uri>(element, element2)
|
||||
val preProcessImages = uploadModel!!.preProcessImages(uriList, "image/jpeg", mock(Place::class.java), "external") { _, _ -> }
|
||||
val preProcessImages = uploadModel!!.preProcessImages(getMediaList(), mock(Place::class.java), "external") { _, _ -> }
|
||||
preProcessImages.doOnComplete {
|
||||
assertTrue(uploadModel!!.items.size == 2)
|
||||
}
|
||||
|
|
@ -95,46 +89,31 @@ class UploadModelTest {
|
|||
|
||||
@Test
|
||||
fun verifyPreviousNotAvailable() {
|
||||
val element = getElement()
|
||||
val element2 = getElement()
|
||||
var uriList: List<Uri> = mutableListOf<Uri>(element, element2)
|
||||
uploadModel!!.preProcessImages(uriList, "image/jpeg", mock(Place::class.java), "external") { _, _ -> }
|
||||
uploadModel!!.preProcessImages(getMediaList(), mock(Place::class.java), "external") { _, _ -> }
|
||||
assertFalse(uploadModel!!.isPreviousAvailable)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyNextAvailable() {
|
||||
val element = getElement()
|
||||
val element2 = getElement()
|
||||
var uriList: List<Uri> = mutableListOf<Uri>(element, element2)
|
||||
uploadModel!!.preProcessImages(uriList, "image/jpeg", mock(Place::class.java), "external") { _, _ -> }
|
||||
uploadModel!!.preProcessImages(getMediaList(), mock(Place::class.java), "external") { _, _ -> }
|
||||
assertTrue(uploadModel!!.isNextAvailable)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isSubmitAvailable() {
|
||||
val element = getElement()
|
||||
val element2 = getElement()
|
||||
var uriList: List<Uri> = mutableListOf<Uri>(element, element2)
|
||||
uploadModel!!.preProcessImages(uriList, "image/jpeg", mock(Place::class.java), "external") { _, _ -> }
|
||||
uploadModel!!.preProcessImages(getMediaList(), mock(Place::class.java), "external") { _, _ -> }
|
||||
assertTrue(uploadModel!!.isNextAvailable)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getCurrentStep() {
|
||||
val element = getElement()
|
||||
val element2 = getElement()
|
||||
var uriList: List<Uri> = mutableListOf<Uri>(element, element2)
|
||||
uploadModel!!.preProcessImages(uriList, "image/jpeg", mock(Place::class.java), "external") { _, _ -> }
|
||||
uploadModel!!.preProcessImages(getMediaList(), mock(Place::class.java), "external") { _, _ -> }
|
||||
assertTrue(uploadModel!!.currentStep == 1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getStepCount() {
|
||||
val element = getElement()
|
||||
val element2 = getElement()
|
||||
var uriList: List<Uri> = mutableListOf<Uri>(element, element2)
|
||||
val preProcessImages = uploadModel!!.preProcessImages(uriList, "image/jpeg", mock(Place::class.java), "external") { _, _ -> }
|
||||
val preProcessImages = uploadModel!!.preProcessImages(getMediaList(), mock(Place::class.java), "external") { _, _ -> }
|
||||
preProcessImages.doOnComplete {
|
||||
assertTrue(uploadModel!!.stepCount == 4)
|
||||
}
|
||||
|
|
@ -142,10 +121,7 @@ class UploadModelTest {
|
|||
|
||||
@Test
|
||||
fun getCount() {
|
||||
val element = getElement()
|
||||
val element2 = getElement()
|
||||
var uriList: List<Uri> = mutableListOf<Uri>(element, element2)
|
||||
val preProcessImages = uploadModel!!.preProcessImages(uriList, "image/jpeg", mock(Place::class.java), "external") { _, _ -> }
|
||||
val preProcessImages = uploadModel!!.preProcessImages(getMediaList(), mock(Place::class.java), "external") { _, _ -> }
|
||||
preProcessImages.doOnComplete {
|
||||
assertTrue(uploadModel!!.count == 2)
|
||||
}
|
||||
|
|
@ -153,10 +129,7 @@ class UploadModelTest {
|
|||
|
||||
@Test
|
||||
fun getUploads() {
|
||||
val element = getElement()
|
||||
val element2 = getElement()
|
||||
var uriList: List<Uri> = mutableListOf<Uri>(element, element2)
|
||||
val preProcessImages = uploadModel!!.preProcessImages(uriList, "image/jpeg", mock(Place::class.java), "external") { _, _ -> }
|
||||
val preProcessImages = uploadModel!!.preProcessImages(getMediaList(), mock(Place::class.java), "external") { _, _ -> }
|
||||
preProcessImages.doOnComplete {
|
||||
assertTrue(uploadModel!!.uploads.size == 2)
|
||||
}
|
||||
|
|
@ -164,19 +137,13 @@ class UploadModelTest {
|
|||
|
||||
@Test
|
||||
fun isTopCardState() {
|
||||
val element = getElement()
|
||||
val element2 = getElement()
|
||||
var uriList: List<Uri> = mutableListOf<Uri>(element, element2)
|
||||
uploadModel!!.preProcessImages(uriList, "image/jpeg", mock(Place::class.java), "external") { _, _ -> }
|
||||
uploadModel!!.preProcessImages(getMediaList(), mock(Place::class.java), "external") { _, _ -> }
|
||||
assertTrue(uploadModel!!.isTopCardState)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun next() {
|
||||
val element = getElement()
|
||||
val element2 = getElement()
|
||||
var uriList: List<Uri> = mutableListOf<Uri>(element, element2)
|
||||
uploadModel!!.preProcessImages(uriList, "image/jpeg", mock(Place::class.java), "external") { _, _ -> }
|
||||
uploadModel!!.preProcessImages(getMediaList(), mock(Place::class.java), "external") { _, _ -> }
|
||||
assertTrue(uploadModel!!.currentStep == 1)
|
||||
uploadModel!!.next()
|
||||
assertTrue(uploadModel!!.currentStep == 2)
|
||||
|
|
@ -184,10 +151,7 @@ class UploadModelTest {
|
|||
|
||||
@Test
|
||||
fun previous() {
|
||||
val element = getElement()
|
||||
val element2 = getElement()
|
||||
var uriList: List<Uri> = mutableListOf<Uri>(element, element2)
|
||||
uploadModel!!.preProcessImages(uriList, "image/jpeg", mock(Place::class.java), "external") { _, _ -> }
|
||||
uploadModel!!.preProcessImages(getMediaList(), mock(Place::class.java), "external") { _, _ -> }
|
||||
assertTrue(uploadModel!!.currentStep == 1)
|
||||
uploadModel!!.next()
|
||||
assertTrue(uploadModel!!.currentStep == 2)
|
||||
|
|
@ -197,18 +161,22 @@ class UploadModelTest {
|
|||
|
||||
@Test
|
||||
fun isShowingItem() {
|
||||
val element = getElement()
|
||||
val element2 = getElement()
|
||||
var uriList: List<Uri> = mutableListOf<Uri>(element, element2)
|
||||
val preProcessImages = uploadModel!!.preProcessImages(uriList, "image/jpeg", mock(Place::class.java), "external") { _, _ -> }
|
||||
val preProcessImages = uploadModel!!.preProcessImages(getMediaList(), mock(Place::class.java), "external") { _, _ -> }
|
||||
preProcessImages.doOnComplete {
|
||||
assertTrue(uploadModel!!.isShowingItem)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getElement(): Uri {
|
||||
val mock = mock(Uri::class.java)
|
||||
`when`(mock.path).thenReturn(UUID.randomUUID().toString() + "/file.jpg")
|
||||
private fun getMediaList(): List<UploadableFile> {
|
||||
val element = getElement()
|
||||
val element2 = getElement()
|
||||
var uriList: List<UploadableFile> = mutableListOf(element, element2)
|
||||
return uriList
|
||||
}
|
||||
|
||||
private fun getElement(): UploadableFile {
|
||||
val mock = mock(UploadableFile::class.java)
|
||||
`when`(mock.filePath).thenReturn(UUID.randomUUID().toString() + "/filePath.jpg")
|
||||
return mock
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package fr.free.nrw.commons.upload
|
||||
|
||||
import android.net.Uri
|
||||
import fr.free.nrw.commons.contributions.UploadableFile
|
||||
import fr.free.nrw.commons.mwapi.MediaWikiApi
|
||||
import fr.free.nrw.commons.nearby.Place
|
||||
import io.reactivex.Observable
|
||||
|
|
@ -26,8 +26,7 @@ class UploadPresenterTest {
|
|||
@Throws(Exception::class)
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
`when`(uploadModel!!.preProcessImages(ArgumentMatchers.anyListOf(Uri::class.java),
|
||||
ArgumentMatchers.anyString(),
|
||||
`when`(uploadModel!!.preProcessImages(ArgumentMatchers.anyListOf(UploadableFile::class.java),
|
||||
ArgumentMatchers.any(Place::class.java),
|
||||
ArgumentMatchers.anyString(),
|
||||
ArgumentMatchers.any(SimilarImageInterface::class.java)))
|
||||
|
|
@ -36,9 +35,9 @@ class UploadPresenterTest {
|
|||
|
||||
@Test
|
||||
fun receiveMultipleItems() {
|
||||
val element = Mockito.mock(Uri::class.java)
|
||||
val element2 = Mockito.mock(Uri::class.java)
|
||||
var uriList: List<Uri> = mutableListOf<Uri>(element, element2)
|
||||
uploadPresenter!!.receive(uriList, "image/jpeg", "external", mock(Place::class.java))
|
||||
val element = Mockito.mock(UploadableFile::class.java)
|
||||
val element2 = Mockito.mock(UploadableFile::class.java)
|
||||
var uriList: List<UploadableFile> = mutableListOf<UploadableFile>(element, element2)
|
||||
uploadPresenter!!.receive(uriList, "external", mock(Place::class.java))
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue