From 55353534801e5932ec7af483be7c504fe6329545 Mon Sep 17 00:00:00 2001 From: Madhur Gupta <30932899+madhurgupta10@users.noreply.github.com> Date: Sat, 6 Nov 2021 15:27:23 +0530 Subject: [PATCH] Add RecentSearchesFragment Unit Tests (#4675) --- .../RecentSearchesFragment.java | 91 +++++----- .../nrw/commons/TestCommonsApplication.kt | 1 + .../RecentSearchesFragmentUnitTest.kt | 158 ++++++++++++++++++ 3 files changed, 212 insertions(+), 38 deletions(-) create mode 100644 app/src/test/kotlin/fr/free/nrw/commons/explore/recentsearches/RecentSearchesFragmentUnitTest.kt diff --git a/app/src/main/java/fr/free/nrw/commons/explore/recentsearches/RecentSearchesFragment.java b/app/src/main/java/fr/free/nrw/commons/explore/recentsearches/RecentSearchesFragment.java index ba2a9340b..e3b607106 100644 --- a/app/src/main/java/fr/free/nrw/commons/explore/recentsearches/RecentSearchesFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/explore/recentsearches/RecentSearchesFragment.java @@ -1,5 +1,7 @@ package fr.free.nrw.commons.explore.recentsearches; +import android.content.Context; +import android.content.DialogInterface; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -9,18 +11,15 @@ import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; - +import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; - -import java.util.List; - -import javax.inject.Inject; - import butterknife.BindView; import butterknife.ButterKnife; import fr.free.nrw.commons.R; import fr.free.nrw.commons.di.CommonsDaggerSupportFragment; import fr.free.nrw.commons.explore.SearchActivity; +import java.util.List; +import javax.inject.Inject; /** @@ -52,24 +51,7 @@ public class RecentSearchesFragment extends CommonsDaggerSupportFragment { } recent_searches_delete_button.setOnClickListener(v -> { - new AlertDialog.Builder(getContext()) - .setMessage(getString(R.string.delete_recent_searches_dialog)) - .setPositiveButton(android.R.string.yes, (dialog, which) -> { - recentSearchesDao.deleteAll(); - recent_searches_delete_button.setVisibility(View.GONE); - recent_searches_text_view.setText(R.string.no_recent_searches); - Toast.makeText(getContext(), getString(R.string.search_history_deleted), - Toast.LENGTH_SHORT).show(); - recentSearches = recentSearchesDao.recentSearches(10); - adapter = new ArrayAdapter<>(getContext(), R.layout.item_recent_searches, - recentSearches); - recentSearchesList.setAdapter(adapter); - adapter.notifyDataSetChanged(); - dialog.dismiss(); - }) - .setNegativeButton(android.R.string.no, null) - .create() - .show(); + showDeleteRecentAlertDialog(requireContext()); }); adapter = new ArrayAdapter<>(requireContext(), R.layout.item_recent_searches, @@ -78,26 +60,59 @@ public class RecentSearchesFragment extends CommonsDaggerSupportFragment { recentSearchesList.setOnItemClickListener((parent, view, position, id) -> ( (SearchActivity) getContext()).updateText(recentSearches.get(position))); recentSearchesList.setOnItemLongClickListener((parent, view, position, id) -> { - new AlertDialog.Builder(getContext()) - .setMessage(R.string.delete_search_dialog) - .setPositiveButton(getString(R.string.delete).toUpperCase(), ((dialog, which) -> { - recentSearchesDao.delete(recentSearchesDao.find(recentSearches.get(position))); - recentSearches = recentSearchesDao.recentSearches(10); - adapter = new ArrayAdapter<>(getContext(), R.layout.item_recent_searches, - recentSearches); - recentSearchesList.setAdapter(adapter); - adapter.notifyDataSetChanged(); - dialog.dismiss(); - })) - .setNegativeButton(android.R.string.cancel, null) - .create() - .show(); + showDeleteAlertDialog(requireContext(), position); return true; }); updateRecentSearches(); return rootView; } + private void showDeleteRecentAlertDialog(@NonNull final Context context) { + new AlertDialog.Builder(context) + .setMessage(getString(R.string.delete_recent_searches_dialog)) + .setPositiveButton(android.R.string.yes, + (dialog, which) -> setDeleteRecentPositiveButton(context, dialog)) + .setNegativeButton(android.R.string.no, null) + .create() + .show(); + } + + private void setDeleteRecentPositiveButton(@NonNull final Context context, + final DialogInterface dialog) { + recentSearchesDao.deleteAll(); + recent_searches_delete_button.setVisibility(View.GONE); + recent_searches_text_view.setText(R.string.no_recent_searches); + Toast.makeText(getContext(), getString(R.string.search_history_deleted), + Toast.LENGTH_SHORT).show(); + recentSearches = recentSearchesDao.recentSearches(10); + adapter = new ArrayAdapter<>(context, R.layout.item_recent_searches, + recentSearches); + recentSearchesList.setAdapter(adapter); + adapter.notifyDataSetChanged(); + dialog.dismiss(); + } + + private void showDeleteAlertDialog(@NonNull final Context context, final int position) { + new AlertDialog.Builder(context) + .setMessage(R.string.delete_search_dialog) + .setPositiveButton(getString(R.string.delete).toUpperCase(), + ((dialog, which) -> setDeletePositiveButton(context, dialog, position))) + .setNegativeButton(android.R.string.cancel, null) + .create() + .show(); + } + + private void setDeletePositiveButton(@NonNull final Context context, + final DialogInterface dialog, final int position) { + recentSearchesDao.delete(recentSearchesDao.find(recentSearches.get(position))); + recentSearches = recentSearchesDao.recentSearches(10); + adapter = new ArrayAdapter<>(context, R.layout.item_recent_searches, + recentSearches); + recentSearchesList.setAdapter(adapter); + adapter.notifyDataSetChanged(); + dialog.dismiss(); + } + /** * This method is called on back press of activity so we are updating the list from database to * refresh the recent searches list. diff --git a/app/src/test/kotlin/fr/free/nrw/commons/TestCommonsApplication.kt b/app/src/test/kotlin/fr/free/nrw/commons/TestCommonsApplication.kt index de3081e76..e5f4ce5ae 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/TestCommonsApplication.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/TestCommonsApplication.kt @@ -25,6 +25,7 @@ class TestCommonsApplication : Application() { .build() } super.onCreate() + setTheme(R.style.Theme_AppCompat) context=applicationContext } diff --git a/app/src/test/kotlin/fr/free/nrw/commons/explore/recentsearches/RecentSearchesFragmentUnitTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/explore/recentsearches/RecentSearchesFragmentUnitTest.kt new file mode 100644 index 000000000..57bb5e551 --- /dev/null +++ b/app/src/test/kotlin/fr/free/nrw/commons/explore/recentsearches/RecentSearchesFragmentUnitTest.kt @@ -0,0 +1,158 @@ +package fr.free.nrw.commons.explore.recentsearches + +import android.content.Context +import android.content.DialogInterface +import android.view.LayoutInflater +import android.view.View +import android.widget.ArrayAdapter +import android.widget.ImageView +import android.widget.ListView +import android.widget.TextView +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentTransaction +import com.nhaarman.mockitokotlin2.whenever +import fr.free.nrw.commons.R +import fr.free.nrw.commons.TestAppAdapter +import fr.free.nrw.commons.TestCommonsApplication +import fr.free.nrw.commons.contributions.MainActivity +import org.junit.Assert +import org.junit.Before +import org.junit.Test +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.annotation.Config +import org.robolectric.annotation.LooperMode +import org.wikipedia.AppAdapter +import java.lang.reflect.Method + +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [21], application = TestCommonsApplication::class) +@LooperMode(LooperMode.Mode.PAUSED) +class RecentSearchesFragmentUnitTest { + + private lateinit var fragment: RecentSearchesFragment + private lateinit var fragmentManager: FragmentManager + private lateinit var context: Context + private lateinit var view: View + private lateinit var layoutInflater: LayoutInflater + + @Mock + private lateinit var recentSearchesDao: RecentSearchesDao + + @Mock + private lateinit var imageView: ImageView + + @Mock + private lateinit var textView: TextView + + @Mock + private lateinit var listView: ListView + + @Mock + private lateinit var adapter: ArrayAdapter<*> + + @Mock + private lateinit var dialog: DialogInterface + + @Mock + private lateinit var recentSearches: List + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + context = RuntimeEnvironment.application.applicationContext + + AppAdapter.set(TestAppAdapter()) + + val activity = Robolectric.buildActivity(MainActivity::class.java).create().get() + fragment = RecentSearchesFragment() + fragmentManager = activity.supportFragmentManager + val fragmentTransaction: FragmentTransaction = fragmentManager.beginTransaction() + fragmentTransaction.add(fragment, null) + fragmentTransaction.commitNowAllowingStateLoss() + + layoutInflater = LayoutInflater.from(activity) + view = LayoutInflater.from(activity) + .inflate(R.layout.fragment_leaderboard, null) as View + + Whitebox.setInternalState(fragment, "recentSearchesDao", recentSearchesDao) + Whitebox.setInternalState(fragment, "recent_searches_delete_button", imageView) + Whitebox.setInternalState(fragment, "recent_searches_text_view", textView) + Whitebox.setInternalState(fragment, "adapter", adapter) + Whitebox.setInternalState(fragment, "recentSearchesList", listView) + Whitebox.setInternalState(fragment, "recentSearches", listOf("string")) + } + + @Test + @Throws(Exception::class) + fun checkFragmentNotNull() { + Assert.assertNotNull(fragment) + } + + @Test + @Throws(Exception::class) + fun testOnCreateView() { + fragment.onCreateView(layoutInflater, null, null) + } + + @Test + @Throws(Exception::class) + fun testOnResume() { + whenever(recentSearchesDao.recentSearches(10)).thenReturn(mutableListOf("search1")) + fragment.onResume() + } + + @Test + @Throws(Exception::class) + fun testShowDeleteRecentAlertDialog() { + val method: Method = RecentSearchesFragment::class.java.getDeclaredMethod( + "showDeleteRecentAlertDialog", + Context::class.java + ) + method.isAccessible = true + method.invoke(fragment, context) + } + + @Test + @Throws(Exception::class) + fun testSetDeleteRecentPositiveButton() { + val method: Method = RecentSearchesFragment::class.java.getDeclaredMethod( + "setDeleteRecentPositiveButton", + Context::class.java, + DialogInterface::class.java + ) + method.isAccessible = true + method.invoke(fragment, context, dialog) + } + + @Test + @Throws(Exception::class) + fun testShowDeleteAlertDialog() { + val method: Method = RecentSearchesFragment::class.java.getDeclaredMethod( + "showDeleteAlertDialog", + Context::class.java, + Int::class.java + ) + method.isAccessible = true + method.invoke(fragment, context, 0) + } + + @Test + @Throws(Exception::class) + fun testSetDeletePositiveButton() { + val method: Method = RecentSearchesFragment::class.java.getDeclaredMethod( + "setDeletePositiveButton", + Context::class.java, + DialogInterface::class.java, + Int::class.java + ) + method.isAccessible = true + method.invoke(fragment, context, dialog, 0) + } + +} \ No newline at end of file