mirror of
				https://github.com/commons-app/apps-android-commons.git
				synced 2025-10-30 22:34:02 +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
				
			
		|  | @ -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
	
	 Vivek Maskara
						Vivek Maskara