diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/FolderFragment.kt b/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/FolderFragment.kt index 1d5901c9d..e43c0798c 100644 --- a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/FolderFragment.kt +++ b/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/FolderFragment.kt @@ -4,9 +4,11 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.ProgressBar import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView import fr.free.nrw.commons.R import fr.free.nrw.commons.customselector.helper.ImageHelper import fr.free.nrw.commons.customselector.model.Result @@ -16,7 +18,6 @@ import fr.free.nrw.commons.customselector.ui.adapter.FolderAdapter import fr.free.nrw.commons.di.CommonsDaggerSupportFragment import fr.free.nrw.commons.media.MediaClient import fr.free.nrw.commons.upload.FileProcessor -import kotlinx.android.synthetic.main.fragment_custom_selector.* import kotlinx.android.synthetic.main.fragment_custom_selector.view.* import javax.inject.Inject @@ -27,6 +28,12 @@ class FolderFragment : CommonsDaggerSupportFragment() { */ private var viewModel: CustomSelectorViewModel? = null + /** + * View Elements + */ + private var selectorRV: RecyclerView? = null + private var loader: ProgressBar? = null + /** * View Model Factory. */ @@ -75,6 +82,8 @@ class FolderFragment : CommonsDaggerSupportFragment() { val root = inflater.inflate(R.layout.fragment_custom_selector, container, false) folderAdapter = FolderAdapter(activity!!, activity as FolderClickListener) gridLayoutManager = GridLayoutManager(context, columnCount()) + selectorRV = root.selector_rv + loader = root.loader with(root.selector_rv){ this.layoutManager = gridLayoutManager setHasFixedSize(true) @@ -96,9 +105,13 @@ class FolderFragment : CommonsDaggerSupportFragment() { val folders = ImageHelper.folderListFromImages(result.images) folderAdapter.init(folders) folderAdapter.notifyDataSetChanged() - selector_rv.visibility = View.VISIBLE + selectorRV?.let { + it.visibility = View.VISIBLE + } + } + loader?.let { + it.visibility = if (result.status is CallbackStatus.FETCHING) View.VISIBLE else View.GONE } - loader.visibility = if (result.status is CallbackStatus.FETCHING) View.VISIBLE else View.GONE } /** diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageFragment.kt b/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageFragment.kt index a2de0ed29..f1583c54f 100644 --- a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageFragment.kt +++ b/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageFragment.kt @@ -4,9 +4,11 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.ProgressBar import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView import fr.free.nrw.commons.R import fr.free.nrw.commons.customselector.helper.ImageHelper import fr.free.nrw.commons.customselector.listeners.ImageSelectListener @@ -28,7 +30,13 @@ class ImageFragment: CommonsDaggerSupportFragment() { /** * View model for images. */ - private lateinit var viewModel: CustomSelectorViewModel + private var viewModel: CustomSelectorViewModel? = null + + /** + * View Elements + */ + private var selectorRV: RecyclerView? = null + private var loader: ProgressBar? = null /** * View model Factory. @@ -98,10 +106,13 @@ class ImageFragment: CommonsDaggerSupportFragment() { this.adapter = imageAdapter } - viewModel.result.observe(viewLifecycleOwner, Observer{ + viewModel?.result?.observe(viewLifecycleOwner, Observer{ handleResult(it) }) + selectorRV = root.selector_rv + loader = root.loader + return root } @@ -113,13 +124,19 @@ class ImageFragment: CommonsDaggerSupportFragment() { val images = result.images if(images.isNotEmpty()) { imageAdapter.init(ImageHelper.filterImages(images,bucketId)) - selector_rv.visibility = View.VISIBLE + selectorRV?.let{ + it.visibility = View.VISIBLE + } } else{ - selector_rv.visibility = View.GONE + selectorRV?.let{ + it.visibility = View.GONE + } } } - loader.visibility = if (result.status is CallbackStatus.FETCHING) View.VISIBLE else View.GONE + loader?.let { + it.visibility = if (result.status is CallbackStatus.FETCHING) View.VISIBLE else View.GONE + } } /** diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageLoader.kt b/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageLoader.kt index f2d4d5709..5680cc775 100644 --- a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageLoader.kt +++ b/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageLoader.kt @@ -19,6 +19,7 @@ import timber.log.Timber import java.io.IOException import java.net.UnknownHostException import java.util.* +import java.util.concurrent.TimeUnit import javax.inject.Inject import kotlin.collections.HashMap @@ -179,7 +180,8 @@ class ImageLoader @Inject constructor( return Result.TRUE } else { uploadedStatus.lastUpdated?.let { - if (it.date >= Calendar.getInstance().time.date - INVALIDATE_DAY_COUNT) { + val duration = Calendar.getInstance().time.time - it.time + if (TimeUnit.MILLISECONDS.toDays(duration) < INVALIDATE_DAY_COUNT) { return Result.FALSE } } @@ -218,7 +220,7 @@ class ImageLoader @Inject constructor( } companion object { - const val INVALIDATE_DAY_COUNT: Int = 7 + const val INVALIDATE_DAY_COUNT: Long = 7 } } \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/explore/ExploreListRootFragment.java b/app/src/main/java/fr/free/nrw/commons/explore/ExploreListRootFragment.java index 32b38fea7..e88f14b55 100644 --- a/app/src/main/java/fr/free/nrw/commons/explore/ExploreListRootFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/explore/ExploreListRootFragment.java @@ -40,7 +40,7 @@ public class ExploreListRootFragment extends CommonsDaggerSupportFragment implem featuredArguments.putString("categoryName", title); listFragment.setArguments(featuredArguments); } - + @Nullable @Override public View onCreateView(@NonNull final LayoutInflater inflater, diff --git a/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorActivityTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorActivityTest.kt new file mode 100644 index 000000000..6d55a49e2 --- /dev/null +++ b/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorActivityTest.kt @@ -0,0 +1,96 @@ +package fr.free.nrw.commons.customselector.ui.selector + +import android.net.Uri +import android.os.Bundle +import fr.free.nrw.commons.TestCommonsApplication +import fr.free.nrw.commons.customselector.model.Folder +import fr.free.nrw.commons.customselector.model.Image +import org.junit.Before +import org.junit.Test +import org.junit.jupiter.api.Assertions.assertNotNull +import org.junit.runner.RunWith +import org.mockito.MockitoAnnotations +import org.robolectric.Robolectric +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config + +/** + * Custom Selector Activity Test + */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [21], application = TestCommonsApplication::class) +class CustomSelectorActivityTest { + + private lateinit var activity: CustomSelectorActivity + + /** + * Set up the tests. + */ + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + activity = Robolectric.buildActivity(CustomSelectorActivity::class.java) + .get() + val onCreate = activity.javaClass.getDeclaredMethod("onCreate", Bundle::class.java) + onCreate.isAccessible = true + onCreate.invoke(activity, null) + } + + /** + * Test activity not null. + */ + @Test + @Throws(Exception::class) + fun testActivityNotNull() { + assertNotNull(activity) + } + + /** + * Test changeTitle function. + */ + @Test + @Throws(Exception::class) + fun testChangeTitle() { + val func = activity.javaClass.getDeclaredMethod("changeTitle", String::class.java) + func.isAccessible = true + func.invoke(activity, "test") + } + + /** + * Test onFolderClick function. + */ + @Test + @Throws(Exception::class) + fun testOnFolderClick() { + activity.onFolderClick(Folder(1, "test", arrayListOf())); + } + + /** + * Test selectedImagesChanged function. + */ + @Test + @Throws(Exception::class) + fun testOnSelectedImagesChanged() { + activity.onSelectedImagesChanged(ArrayList()) + } + + /** + * Test onDone function. + */ + @Test + @Throws(Exception::class) + fun testOnDone() { + activity.onDone() + activity.onSelectedImagesChanged(ArrayList(arrayListOf(Image(1, "test", Uri.parse("test"), "test", 1)))); + activity.onDone() + } + + /** + * Test onBackPressed Function. + */ + @Test + @Throws(Exception::class) + fun testOnBackPressed() { + activity.onBackPressed() + } +} \ No newline at end of file diff --git a/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorViewModelTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorViewModelTest.kt new file mode 100644 index 000000000..309392d4d --- /dev/null +++ b/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorViewModelTest.kt @@ -0,0 +1,41 @@ +package fr.free.nrw.commons.customselector.ui.selector + +import android.content.Context +import org.junit.Before +import org.junit.Test +import org.mockito.Mock +import org.mockito.MockitoAnnotations + +/** + * Custom Selector View Model test. + */ +class CustomSelectorViewModelTest { + + private lateinit var viewModel: CustomSelectorViewModel + + @Mock + private lateinit var imageFileLoader: ImageFileLoader + + @Mock + private lateinit var context: Context + + /** + * Set up the test. + */ + @Before + fun setUp(){ + MockitoAnnotations.initMocks(this) + viewModel = CustomSelectorViewModel(context, imageFileLoader); + } + + /** + * Test onCleared(); + */ + @Test + fun testOnCleared(){ + val func = viewModel.javaClass.getDeclaredMethod("onCleared") + func.isAccessible = true + func.invoke(viewModel); + } + +} \ No newline at end of file diff --git a/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/FolderFragmentTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/FolderFragmentTest.kt new file mode 100644 index 000000000..53094d6f7 --- /dev/null +++ b/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/FolderFragmentTest.kt @@ -0,0 +1,130 @@ +package fr.free.nrw.commons.customselector.ui.selector + +import android.content.Context +import android.os.Bundle +import android.os.Looper +import android.view.LayoutInflater +import android.view.View +import fr.free.nrw.commons.customselector.model.Result +import android.widget.ProgressBar +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentTransaction +import androidx.recyclerview.widget.RecyclerView +import com.facebook.drawee.backends.pipeline.Fresco +import com.facebook.soloader.SoLoader +import fr.free.nrw.commons.R +import fr.free.nrw.commons.TestAppAdapter +import fr.free.nrw.commons.TestCommonsApplication +import fr.free.nrw.commons.customselector.model.CallbackStatus +import fr.free.nrw.commons.customselector.ui.adapter.FolderAdapter +import org.junit.Before +import org.junit.Test +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.MockitoAnnotations +import org.powermock.reflect.Whitebox +import org.robolectric.Robolectric +import org.robolectric.RobolectricTestRunner +import org.robolectric.RuntimeEnvironment +import org.robolectric.Shadows +import org.robolectric.annotation.Config +import org.robolectric.annotation.LooperMode +import org.wikipedia.AppAdapter +import java.lang.reflect.Field + +/** + * Custom Selector Folder Fragment Test. + */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [21], application = TestCommonsApplication::class) +@LooperMode(LooperMode.Mode.PAUSED) +class FolderFragmentTest { + + private lateinit var fragment: FolderFragment + private lateinit var view: View + private lateinit var selectorRV : RecyclerView + private lateinit var loader : ProgressBar + private lateinit var layoutInflater: LayoutInflater + private lateinit var context: Context + private lateinit var viewModelField:Field + + @Mock + private lateinit var adapter: FolderAdapter + + @Mock + private lateinit var savedInstanceState: Bundle + + /** + * Setup the folder fragment. + */ + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + context = RuntimeEnvironment.application.applicationContext + AppAdapter.set(TestAppAdapter()) + SoLoader.setInTestMode() + Fresco.initialize(context) + val activity = Robolectric.buildActivity(CustomSelectorActivity::class.java).create().get() + + fragment = FolderFragment.newInstance() + val fragmentManager: FragmentManager = activity.supportFragmentManager + val fragmentTransaction: FragmentTransaction = fragmentManager.beginTransaction() + fragmentTransaction.add(fragment, null) + fragmentTransaction.commit() + + layoutInflater = LayoutInflater.from(activity) + view = layoutInflater.inflate(R.layout.fragment_custom_selector, null) as View + + selectorRV = view.findViewById(R.id.selector_rv) + loader = view.findViewById(R.id.loader) + + Whitebox.setInternalState(fragment, "folderAdapter", adapter) + Whitebox.setInternalState(fragment, "selectorRV", selectorRV ) + Whitebox.setInternalState(fragment, "loader", loader) + + viewModelField = fragment.javaClass.getDeclaredField("viewModel") + viewModelField.isAccessible = true + } + + /** + * Test onCreateView + */ + @Test + @Throws(Exception::class) + fun testOnCreateView() { + Shadows.shadowOf(Looper.getMainLooper()).idle() + viewModelField.set(fragment, null) + fragment.onCreateView(layoutInflater, null, savedInstanceState) + } + + /** + * Test onCreate + */ + @Test + @Throws(Exception::class) + fun testOnCreate() { + Shadows.shadowOf(Looper.getMainLooper()).idle() + fragment.onCreate(savedInstanceState) + } + + /** + * Test columnCount. + */ + @Test + fun testColumnCount() { + val func = fragment.javaClass.getDeclaredMethod("columnCount") + func.isAccessible = true + assertEquals(2, func.invoke(fragment)) + } + + /** + * Test handleResult. + */ + @Test + fun testHandleResult() { + val func = fragment.javaClass.getDeclaredMethod("handleResult", Result::class.java) + func.isAccessible = true + func.invoke(fragment, Result(CallbackStatus.SUCCESS, arrayListOf())) + } +} \ No newline at end of file diff --git a/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/ImageFileLoaderTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/ImageFileLoaderTest.kt new file mode 100644 index 000000000..e30d47216 --- /dev/null +++ b/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/ImageFileLoaderTest.kt @@ -0,0 +1,123 @@ +package fr.free.nrw.commons.customselector.ui.selector + +import android.content.ContentResolver +import android.content.Context +import android.provider.MediaStore +import com.nhaarman.mockitokotlin2.anyOrNull +import com.nhaarman.mockitokotlin2.doReturn +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.same +import fr.free.nrw.commons.TestCommonsApplication +import fr.free.nrw.commons.customselector.listeners.ImageLoaderListener +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.`when` +import org.mockito.MockitoAnnotations +import org.powermock.reflect.Whitebox +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import org.robolectric.annotation.LooperMode +import org.robolectric.fakes.RoboCursor +import java.io.File +import kotlin.coroutines.CoroutineContext + +/** + * Custom Selector Image File loader test. + */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [21], application = TestCommonsApplication::class) +@LooperMode(LooperMode.Mode.PAUSED) +class ImageFileLoaderTest { + + @Mock + private lateinit var mockContentResolver: ContentResolver + + @Mock + private lateinit var context: Context; + + @Mock + private lateinit var imageLoaderListener: ImageLoaderListener + + @Mock + private lateinit var coroutineScope: CoroutineScope + + private lateinit var imageCursor: RoboCursor + private lateinit var coroutineContext: CoroutineContext + private lateinit var projection: List + private lateinit var imageFileLoader: ImageFileLoader + + /** + * Setup before tests. + */ + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + coroutineContext = Dispatchers.Main + imageCursor = RoboCursor() + imageFileLoader = ImageFileLoader(context) + projection = listOf( + MediaStore.Images.Media._ID, + MediaStore.Images.Media.DISPLAY_NAME, + MediaStore.Images.Media.DATA, + MediaStore.Images.Media.BUCKET_ID, + MediaStore.Images.Media.BUCKET_DISPLAY_NAME + ) + + Whitebox.setInternalState(imageFileLoader, "coroutineContext", coroutineContext) + } + + /** + * Test loading device images. + */ + @Test + fun testLoadDeviceImages() { + imageFileLoader.loadDeviceImages(imageLoaderListener, coroutineScope) + } + + /** + * Test get images from the device function. + */ + @Test + fun testGetImages() { + val func = imageFileLoader.javaClass.getDeclaredMethod( + "getImages", + ImageLoaderListener::class.java + ) + func.isAccessible = true + + val image1 = arrayOf(1, "imageLoaderTestFile", "src/test/resources/imageLoaderTestFile", 1, "downloads") + val image2 = arrayOf(2, "imageLoaderTestFile", null, 1, "downloads") + File("src/test/resources/imageLoaderTestFile").createNewFile() + + imageCursor.setColumnNames(projection) + imageCursor.setResults(arrayOf(image1, image2)); + + val contentResolver: ContentResolver = mock { + on { + query( + same(MediaStore.Images.Media.EXTERNAL_CONTENT_URI), + anyOrNull(), + anyOrNull(), + anyOrNull(), + anyOrNull() + ) + } doReturn imageCursor; + } + + // test null cursor. + `when`( + context.contentResolver + ).thenReturn(mockContentResolver) + func.invoke(imageFileLoader, imageLoaderListener); + + // test demo cursor. + `when`( + context.contentResolver + ).thenReturn(contentResolver) + func.invoke(imageFileLoader, imageLoaderListener); + } +} \ No newline at end of file diff --git a/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/ImageFragmentTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/ImageFragmentTest.kt new file mode 100644 index 000000000..9794003c8 --- /dev/null +++ b/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/ImageFragmentTest.kt @@ -0,0 +1,135 @@ +package fr.free.nrw.commons.customselector.ui.selector + +import android.content.Context +import android.os.Bundle +import android.os.Looper +import android.view.LayoutInflater +import android.view.View +import android.widget.ProgressBar +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentTransaction +import androidx.recyclerview.widget.RecyclerView +import com.facebook.drawee.backends.pipeline.Fresco +import com.facebook.soloader.SoLoader +import fr.free.nrw.commons.R +import fr.free.nrw.commons.TestAppAdapter +import fr.free.nrw.commons.TestCommonsApplication +import fr.free.nrw.commons.customselector.model.CallbackStatus +import fr.free.nrw.commons.customselector.model.Image +import fr.free.nrw.commons.customselector.model.Result +import fr.free.nrw.commons.customselector.ui.adapter.ImageAdapter +import org.junit.Before +import org.junit.Test +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.MockitoAnnotations +import org.powermock.reflect.Whitebox +import org.robolectric.Robolectric +import org.robolectric.RobolectricTestRunner +import org.robolectric.RuntimeEnvironment +import org.robolectric.Shadows +import org.robolectric.annotation.Config +import org.robolectric.annotation.LooperMode +import org.wikipedia.AppAdapter +import java.lang.reflect.Field + +/** + * Custom Selector Image Fragment Test. + */ +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [21], application = TestCommonsApplication::class) +@LooperMode(LooperMode.Mode.PAUSED) +class ImageFragmentTest { + + private lateinit var fragment: ImageFragment + private lateinit var view: View + private lateinit var selectorRV : RecyclerView + private lateinit var loader : ProgressBar + private lateinit var layoutInflater: LayoutInflater + private lateinit var context: Context + private lateinit var viewModelField: Field + + @Mock + private lateinit var image: Image + + @Mock + private lateinit var adapter: ImageAdapter + + @Mock + private lateinit var savedInstanceState: Bundle + + /** + * Setup the image fragment. + */ + @Before + fun setUp(){ + MockitoAnnotations.initMocks(this) + context = RuntimeEnvironment.application.applicationContext + AppAdapter.set(TestAppAdapter()) + SoLoader.setInTestMode() + Fresco.initialize(context) + val activity = Robolectric.buildActivity(CustomSelectorActivity::class.java).create().get() + + fragment = ImageFragment.newInstance(1) + val fragmentManager: FragmentManager = activity.supportFragmentManager + val fragmentTransaction: FragmentTransaction = fragmentManager.beginTransaction() + fragmentTransaction.add(fragment, null) + fragmentTransaction.commit() + + layoutInflater = LayoutInflater.from(activity) + view = layoutInflater.inflate(R.layout.fragment_custom_selector, null, false) as View + selectorRV = view.findViewById(R.id.selector_rv) + loader = view.findViewById(R.id.loader) + + Whitebox.setInternalState(fragment, "imageAdapter", adapter) + Whitebox.setInternalState(fragment, "selectorRV", selectorRV ) + Whitebox.setInternalState(fragment, "loader", loader) + + viewModelField = fragment.javaClass.getDeclaredField("viewModel") + viewModelField.isAccessible = true + } + + /** + * Test onCreate + */ + @Test + @Throws(Exception::class) + fun testOnCreate(){ + Shadows.shadowOf(Looper.getMainLooper()).idle() + fragment.onCreate(savedInstanceState); + } + + /** + * Test onCreateView + */ + @Test + @Throws(Exception::class) + fun testOnCreateView() { + Shadows.shadowOf(Looper.getMainLooper()).idle() + viewModelField.set(fragment, null) + fragment.onCreateView(layoutInflater, null, savedInstanceState) + } + + /** + * Test handleResult. + */ + @Test + fun testHandleResult(){ + val func = fragment.javaClass.getDeclaredMethod("handleResult", Result::class.java) + func.isAccessible = true + func.invoke(fragment, Result(CallbackStatus.SUCCESS, arrayListOf())) + func.invoke(fragment, Result(CallbackStatus.SUCCESS, arrayListOf(image,image))) + } + + /** + * Test getSpanCount. + */ + @Test + fun testGetSpanCount() { + val func = fragment.javaClass.getDeclaredMethod("getSpanCount") + func.isAccessible = true + assertEquals(3, func.invoke(fragment)) + } + +} \ No newline at end of file diff --git a/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/ImageLoaderTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/ImageLoaderTest.kt new file mode 100644 index 000000000..cb7cf3a50 --- /dev/null +++ b/app/src/test/kotlin/fr/free/nrw/commons/customselector/ui/selector/ImageLoaderTest.kt @@ -0,0 +1,218 @@ +package fr.free.nrw.commons.customselector.ui.selector + +import android.content.ContentResolver +import android.content.Context +import android.net.Uri +import com.nhaarman.mockitokotlin2.any +import com.nhaarman.mockitokotlin2.whenever +import fr.free.nrw.commons.TestCommonsApplication +import fr.free.nrw.commons.customselector.database.UploadedStatus +import fr.free.nrw.commons.customselector.database.UploadedStatusDao +import fr.free.nrw.commons.customselector.model.Image +import fr.free.nrw.commons.customselector.ui.adapter.ImageAdapter +import fr.free.nrw.commons.filepicker.PickedFiles +import fr.free.nrw.commons.filepicker.UploadableFile +import fr.free.nrw.commons.media.MediaClient +import fr.free.nrw.commons.upload.FileProcessor +import fr.free.nrw.commons.upload.FileUtilsWrapper +import io.reactivex.Single +import junit.framework.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.* +import org.powermock.api.mockito.PowerMockito +import org.powermock.core.classloader.annotations.PrepareForTest +import org.powermock.modules.junit4.PowerMockRunner +import org.powermock.reflect.Whitebox +import org.robolectric.annotation.Config +import java.io.File +import java.io.FileInputStream +import java.lang.Exception +import java.util.* +import kotlin.collections.HashMap + +/** + * Image Loader Test. + */ +@RunWith(PowerMockRunner::class) +@PrepareForTest(PickedFiles::class) +@Config(sdk = [21], application = TestCommonsApplication::class) +class ImageLoaderTest { + + @Mock + private lateinit var uri:Uri + + @Mock + private lateinit var mediaClient: MediaClient + + @Mock + private lateinit var single: Single + + @Mock + private lateinit var fileProcessor: FileProcessor + + @Mock + private lateinit var fileUtilsWrapper: FileUtilsWrapper + + @Mock + private lateinit var uploadedStatusDao: UploadedStatusDao + + @Mock + private lateinit var holder: ImageAdapter.ImageViewHolder + + @Mock + private lateinit var context: Context + + @Mock + private lateinit var uploadableFile: UploadableFile + + @Mock + private lateinit var inputStream: FileInputStream + + @Mock + private lateinit var contentResolver: ContentResolver + + @Mock + private lateinit var image: Image; + + private lateinit var imageLoader: ImageLoader; + private var mapImageSHA1: HashMap = HashMap() + private var mapHolderImage : HashMap = HashMap() + private var mapResult: HashMap = HashMap() + + /** + * Setup before test. + */ + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + imageLoader = + ImageLoader(mediaClient, fileProcessor, fileUtilsWrapper, uploadedStatusDao, context) + + Whitebox.setInternalState(imageLoader, "mapImageSHA1", mapImageSHA1); + Whitebox.setInternalState(imageLoader, "mapHolderImage", mapHolderImage); + Whitebox.setInternalState(imageLoader, "mapResult", mapResult); + Whitebox.setInternalState(imageLoader, "context", context) + } + + /** + * Test queryAndSetView. + */ + @Test + fun testQueryAndSetView(){ + // TODO + imageLoader.queryAndSetView(holder,image) + } + + /** + * Test querySha1 + */ + @Test + fun testQuerySha1() { + val func = imageLoader.javaClass.getDeclaredMethod( + "querySHA1", + String::class.java + ) + func.isAccessible = true + + Mockito.`when`(single.blockingGet()).thenReturn(true) + Mockito.`when`(mediaClient.checkFileExistsUsingSha("testSha1")).thenReturn(single) + Mockito.`when`(fileUtilsWrapper.getSHA1(any())).thenReturn("testSha1") + + // test without saving in map. + func.invoke(imageLoader, "testSha1"); + + // test with map save. + mapResult["testSha1"] = ImageLoader.Result.FALSE + func.invoke(imageLoader, "testSha1"); + } + + /** + * Test getSha1 + */ + @Test + @Throws (Exception::class) + fun testGetSha1() { + val func = imageLoader.javaClass.getDeclaredMethod( + "getSHA1", + Image::class.java + ) + func.isAccessible = true + + PowerMockito.mockStatic(PickedFiles::class.java); + BDDMockito.given(PickedFiles.pickedExistingPicture(context, image.uri)) + .willReturn(UploadableFile(uri, File("ABC"))); + + whenever(fileUtilsWrapper.getFileInputStream("ABC")).thenReturn(inputStream) + whenever(fileUtilsWrapper.getSHA1(inputStream)).thenReturn("testSha1") + + Assert.assertEquals("testSha1", func.invoke(imageLoader, image)); + whenever(PickedFiles.pickedExistingPicture(context,Uri.parse("test"))).thenReturn(uploadableFile) + + mapImageSHA1[image] = "testSha2" + Assert.assertEquals("testSha2", func.invoke(imageLoader, image)); + } + + /** + * Test insertIntoUploaded Function. + */ + @Test + @Throws (Exception::class) + fun testInsertIntoUploaded() { + val func = imageLoader.javaClass.getDeclaredMethod( + "insertIntoUploaded", + String::class.java, + String::class.java, + Boolean::class.java, + Boolean::class.java) + func.isAccessible = true + + func.invoke(imageLoader, "", "", true, true) + } + + /** + * Test getImageSha1. + */ + @Test + @Throws (Exception::class) + fun testGetImageSHA1() { + val func = imageLoader.javaClass.getDeclaredMethod( + "getImageSHA1", + Uri::class.java) + func.isAccessible = true + + whenever(contentResolver.openInputStream(uri)).thenReturn(inputStream) + whenever(context.contentResolver).thenReturn(contentResolver) + whenever(fileUtilsWrapper.getSHA1(inputStream)).thenReturn("testSha1") + + Assert.assertEquals("testSha1", func.invoke(imageLoader,uri)) + } + + /** + * Test getResultFromUploadedStatus. + */ + @Test + @Throws (Exception::class) + fun testGetResultFromUploadedStatus() { + val func = imageLoader.javaClass.getDeclaredMethod( + "getResultFromUploadedStatus", + UploadedStatus::class.java) + func.isAccessible = true + + // test Result.TRUE + Assert.assertEquals(ImageLoader.Result.TRUE, + func.invoke(imageLoader, + UploadedStatus("", "", true, true))) + + // test Result.FALSE + Assert.assertEquals(ImageLoader.Result.FALSE, + func.invoke(imageLoader, + UploadedStatus("", "", false, false, Calendar.getInstance().time))) + + // test Result.INVALID + Assert.assertEquals(ImageLoader.Result.INVALID, + func.invoke(imageLoader, UploadedStatus("", "", false, false, Date(0)))) + + } +} \ No newline at end of file diff --git a/app/src/test/resources/imageLoaderTestFile b/app/src/test/resources/imageLoaderTestFile new file mode 100644 index 000000000..e69de29bb