test: coverage
This commit is contained in:
@ -29,6 +29,7 @@ import bou.amine.apps.readerforselfossv2.android.background.LoadingWorker
|
||||
import bou.amine.apps.readerforselfossv2.android.databinding.ActivityHomeBinding
|
||||
import bou.amine.apps.readerforselfossv2.android.fragments.FilterSheetFragment
|
||||
import bou.amine.apps.readerforselfossv2.android.settings.SettingsActivity
|
||||
import bou.amine.apps.readerforselfossv2.android.testing.CountingIdlingResourceSingleton
|
||||
import bou.amine.apps.readerforselfossv2.android.utils.bottombar.maybeShow
|
||||
import bou.amine.apps.readerforselfossv2.android.utils.bottombar.removeBadge
|
||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
||||
@ -84,7 +85,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
repository.offlineOverride = intent.getBooleanExtra("startOffline", false)
|
||||
|
||||
if (fromTabShortcut) {
|
||||
elementsShown = ItemType.fromInt(intent.getIntExtra("shortcutTab", ItemType.UNREAD.position))
|
||||
elementsShown =
|
||||
ItemType.fromInt(intent.getIntExtra("shortcutTab", ItemType.UNREAD.position))
|
||||
}
|
||||
|
||||
setContentView(view)
|
||||
@ -96,8 +98,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
handleSwipeRefreshLayout()
|
||||
|
||||
if (appSettingsService.isItemCachingEnabled()) {
|
||||
CountingIdlingResourceSingleton.increment()
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
repository.tryToCacheItemsAndGetNewOnes()
|
||||
CountingIdlingResourceSingleton.decrement()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -111,9 +115,11 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
binding.swipeRefreshLayout.setOnRefreshListener {
|
||||
repository.offlineOverride = false
|
||||
lastFetchDone = false
|
||||
CountingIdlingResourceSingleton.increment()
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
getElementsAccordingToTab()
|
||||
binding.swipeRefreshLayout.isRefreshing = false
|
||||
CountingIdlingResourceSingleton.decrement()
|
||||
}
|
||||
}
|
||||
|
||||
@ -274,9 +280,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
handleGDPRDialog(appSettingsService.settings.getBoolean("GDPR_shown", false))
|
||||
|
||||
handleRecurringTask()
|
||||
|
||||
CountingIdlingResourceSingleton.increment()
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
repository.handleDBActions()
|
||||
CountingIdlingResourceSingleton.decrement()
|
||||
}
|
||||
|
||||
getElementsAccordingToTab()
|
||||
@ -315,6 +322,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
)
|
||||
binding.recyclerView.layoutManager = layoutManager
|
||||
}
|
||||
|
||||
is GridLayoutManager ->
|
||||
if (appSettingsService.isCardViewEnabled()) {
|
||||
layoutManager =
|
||||
@ -326,6 +334,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS
|
||||
binding.recyclerView.layoutManager = layoutManager
|
||||
}
|
||||
|
||||
else ->
|
||||
if (currentManager == null) {
|
||||
if (!appSettingsService.isCardViewEnabled()) {
|
||||
@ -362,12 +371,14 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
} else {
|
||||
layoutManager.scrollToPositionWithOffset(0, 0)
|
||||
}
|
||||
|
||||
is GridLayoutManager ->
|
||||
if (layoutManager.findFirstCompletelyVisibleItemPosition() == 0) {
|
||||
getElementsAccordingToTab()
|
||||
} else {
|
||||
layoutManager.scrollToPositionWithOffset(0, 0)
|
||||
}
|
||||
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
@ -420,6 +431,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
manager.findLastCompletelyVisibleItemPositions(
|
||||
null,
|
||||
).last()
|
||||
|
||||
is GridLayoutManager -> manager.findLastCompletelyVisibleItemPosition()
|
||||
else -> 0
|
||||
}
|
||||
@ -448,6 +460,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
appendResults: Boolean,
|
||||
itemType: ItemType,
|
||||
) {
|
||||
CountingIdlingResourceSingleton.increment()
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
binding.swipeRefreshLayout.isRefreshing = true
|
||||
repository.displayedItems = itemType
|
||||
@ -459,6 +472,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
}
|
||||
binding.swipeRefreshLayout.isRefreshing = false
|
||||
handleListResult()
|
||||
CountingIdlingResourceSingleton.decrement()
|
||||
}
|
||||
}
|
||||
|
||||
@ -469,8 +483,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
when (oldManager) {
|
||||
is StaggeredGridLayoutManager ->
|
||||
oldManager.findFirstCompletelyVisibleItemPositions(null).last()
|
||||
|
||||
is GridLayoutManager ->
|
||||
oldManager.findFirstCompletelyVisibleItemPosition()
|
||||
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
@ -511,8 +527,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
|
||||
private fun reloadBadges() {
|
||||
if (appSettingsService.isDisplayUnreadCountEnabled() || appSettingsService.isDisplayAllCountEnabled()) {
|
||||
CountingIdlingResourceSingleton.increment()
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
repository.reloadBadges()
|
||||
CountingIdlingResourceSingleton.decrement()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -548,7 +566,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
}
|
||||
|
||||
val searchItem = menu.findItem(R.id.action_search)
|
||||
val searchView = searchItem.getActionView() as SearchView
|
||||
val searchView = searchItem.actionView as SearchView
|
||||
searchView.setOnQueryTextListener(this)
|
||||
|
||||
return true
|
||||
@ -571,18 +589,22 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.issue_tracker -> {
|
||||
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(AppSettingsService.trackerUrl))
|
||||
val browserIntent =
|
||||
Intent(Intent.ACTION_VIEW, Uri.parse(AppSettingsService.trackerUrl))
|
||||
startActivity(browserIntent)
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.action_filter -> {
|
||||
val filterSheetFragment = FilterSheetFragment()
|
||||
filterSheetFragment.show(supportFragmentManager, FilterSheetFragment.TAG)
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.refresh -> {
|
||||
needsConfirmation(R.string.menu_home_refresh, R.string.refresh_dialog_message) {
|
||||
Toast.makeText(this, R.string.refresh_in_progress, Toast.LENGTH_SHORT).show()
|
||||
CountingIdlingResourceSingleton.increment()
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
val updatedRemote = repository.updateRemote()
|
||||
if (updatedRemote) {
|
||||
@ -599,15 +621,17 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
Toast.LENGTH_SHORT,
|
||||
).show()
|
||||
}
|
||||
CountingIdlingResourceSingleton.decrement()
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.readAll -> {
|
||||
if (elementsShown == ItemType.UNREAD) {
|
||||
needsConfirmation(R.string.readAll, R.string.markall_dialog_message) {
|
||||
binding.swipeRefreshLayout.isRefreshing = true
|
||||
|
||||
CountingIdlingResourceSingleton.increment()
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
val success = repository.markAllAsRead(items)
|
||||
if (success) {
|
||||
@ -628,13 +652,19 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
}
|
||||
handleListResult()
|
||||
binding.swipeRefreshLayout.isRefreshing = false
|
||||
CountingIdlingResourceSingleton.decrement()
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.action_disconnect -> {
|
||||
needsConfirmation(R.string.confirm_disconnect_title, R.string.confirm_disconnect_description) {
|
||||
needsConfirmation(
|
||||
R.string.confirm_disconnect_title,
|
||||
R.string.confirm_disconnect_description
|
||||
) {
|
||||
runBlocking {
|
||||
repository.logout()
|
||||
}
|
||||
@ -644,14 +674,17 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.action_settings -> {
|
||||
settingsLauncher.launch(Intent(this, SettingsActivity::class.java))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.action_sources -> {
|
||||
startActivity(Intent(this, SourcesActivity::class.java))
|
||||
return true
|
||||
}
|
||||
|
||||
else -> return super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
@ -678,14 +711,21 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
.build()
|
||||
|
||||
val backgroundWork =
|
||||
PeriodicWorkRequestBuilder<LoadingWorker>(appSettingsService.getRefreshMinutes(), TimeUnit.MINUTES)
|
||||
PeriodicWorkRequestBuilder<LoadingWorker>(
|
||||
appSettingsService.getRefreshMinutes(),
|
||||
TimeUnit.MINUTES
|
||||
)
|
||||
.setConstraints(myConstraints)
|
||||
.addTag("selfoss-loading")
|
||||
.build()
|
||||
|
||||
WorkManager.getInstance(
|
||||
baseContext,
|
||||
).enqueueUniquePeriodicWork("selfoss-loading", ExistingPeriodicWorkPolicy.KEEP, backgroundWork)
|
||||
).enqueueUniquePeriodicWork(
|
||||
"selfoss-loading",
|
||||
ExistingPeriodicWorkPolicy.KEEP,
|
||||
backgroundWork
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -17,6 +17,7 @@ import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import bou.amine.apps.readerforselfossv2.android.databinding.ActivityLoginBinding
|
||||
import bou.amine.apps.readerforselfossv2.android.testing.CountingIdlingResourceSingleton
|
||||
import bou.amine.apps.readerforselfossv2.android.utils.isBaseUrlInvalid
|
||||
import bou.amine.apps.readerforselfossv2.repository.Repository
|
||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||
@ -102,9 +103,14 @@ class LoginActivity : AppCompatActivity(), DIAware {
|
||||
}
|
||||
|
||||
private fun goToMain() {
|
||||
CountingIdlingResourceSingleton.increment()
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
repository.updateApiInformation()
|
||||
ACRA.errorReporter.putCustomData("SELFOSS_API_VERSION", appSettingsService.getApiVersion().toString())
|
||||
ACRA.errorReporter.putCustomData(
|
||||
"SELFOSS_API_VERSION",
|
||||
appSettingsService.getApiVersion().toString()
|
||||
)
|
||||
CountingIdlingResourceSingleton.decrement()
|
||||
}
|
||||
val intent = Intent(this, HomeActivity::class.java)
|
||||
startActivity(intent)
|
||||
@ -139,6 +145,7 @@ class LoginActivity : AppCompatActivity(), DIAware {
|
||||
|
||||
repository.refreshLoginInformation(url, login, password)
|
||||
|
||||
CountingIdlingResourceSingleton.increment()
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
try {
|
||||
repository.updateApiInformation()
|
||||
@ -165,6 +172,7 @@ class LoginActivity : AppCompatActivity(), DIAware {
|
||||
preferenceError()
|
||||
}
|
||||
showProgress(false)
|
||||
CountingIdlingResourceSingleton.decrement()
|
||||
}
|
||||
}
|
||||
|
||||
@ -261,20 +269,25 @@ class LoginActivity : AppCompatActivity(), DIAware {
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.issue_tracker -> {
|
||||
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(AppSettingsService.trackerUrl))
|
||||
val browserIntent =
|
||||
Intent(Intent.ACTION_VIEW, Uri.parse(AppSettingsService.trackerUrl))
|
||||
startActivity(browserIntent)
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.about -> {
|
||||
LibsBuilder()
|
||||
.withAboutIconShown(true)
|
||||
.withAboutVersionShown(true)
|
||||
.withAboutSpecial2("Bug reports").withAboutSpecial2Description(AppSettingsService.trackerUrl)
|
||||
.withAboutSpecial1("Project Page").withAboutSpecial1Description(AppSettingsService.sourceUrl)
|
||||
.withAboutSpecial2("Bug reports")
|
||||
.withAboutSpecial2Description(AppSettingsService.trackerUrl)
|
||||
.withAboutSpecial1("Project Page")
|
||||
.withAboutSpecial1Description(AppSettingsService.sourceUrl)
|
||||
.start(this)
|
||||
true
|
||||
}
|
||||
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@ import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.ProcessLifecycleOwner
|
||||
import androidx.multidex.MultiDexApplication
|
||||
import bou.amine.apps.readerforselfossv2.DI.networkModule
|
||||
import bou.amine.apps.readerforselfossv2.android.testing.TestingHelper
|
||||
import bou.amine.apps.readerforselfossv2.android.viewmodel.AppViewModel
|
||||
import bou.amine.apps.readerforselfossv2.dao.DriverFactory
|
||||
import bou.amine.apps.readerforselfossv2.dao.ReaderForSelfossDB
|
||||
@ -29,23 +30,27 @@ import org.acra.config.toast
|
||||
import org.acra.data.StringFormat
|
||||
import org.acra.ktx.initAcra
|
||||
import org.acra.sender.HttpSender
|
||||
import org.kodein.di.*
|
||||
import org.kodein.di.DI
|
||||
import org.kodein.di.DIAware
|
||||
import org.kodein.di.bind
|
||||
import org.kodein.di.instance
|
||||
import org.kodein.di.singleton
|
||||
|
||||
class MyApp : MultiDexApplication(), DIAware {
|
||||
override val di by DI.lazy {
|
||||
bind<AppSettingsService>() with singleton { AppSettingsService(ACRA.isACRASenderServiceProcess()) }
|
||||
bind<AppSettingsService>() with singleton { AppSettingsService(ACRA.isACRASenderServiceProcess() || TestingHelper().isUnitTest()) }
|
||||
import(networkModule)
|
||||
bind<DriverFactory>() with singleton { DriverFactory(applicationContext) }
|
||||
bind<ReaderForSelfossDB>() with singleton { ReaderForSelfossDB(driverFactory.createDriver()) }
|
||||
bind<Repository>() with
|
||||
singleton {
|
||||
Repository(
|
||||
instance(),
|
||||
instance(),
|
||||
isConnectionAvailable,
|
||||
instance(),
|
||||
)
|
||||
}
|
||||
singleton {
|
||||
Repository(
|
||||
instance(),
|
||||
instance(),
|
||||
isConnectionAvailable,
|
||||
instance(),
|
||||
)
|
||||
}
|
||||
bind<ConnectivityStatus>() with singleton { ConnectivityStatus(applicationContext) }
|
||||
bind<AppViewModel>() with singleton { AppViewModel(repository = instance()) }
|
||||
}
|
||||
@ -194,4 +199,4 @@ class MyApp : MultiDexApplication(), DIAware {
|
||||
super.onPause(owner)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@ import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import bou.amine.apps.readerforselfossv2.android.adapters.SourcesListAdapter
|
||||
import bou.amine.apps.readerforselfossv2.android.databinding.ActivitySourcesBinding
|
||||
import bou.amine.apps.readerforselfossv2.android.testing.CountingIdlingResourceSingleton
|
||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
||||
import bou.amine.apps.readerforselfossv2.repository.Repository
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@ -36,7 +37,8 @@ class SourcesActivity : AppCompatActivity(), DIAware {
|
||||
supportActionBar?.setDisplayShowHomeEnabled(true)
|
||||
|
||||
binding.fab.rippleColor = resources.getColor(R.color.colorAccentDark)
|
||||
binding.fab.backgroundTintList = ColorStateList.valueOf(resources.getColor(R.color.colorAccent))
|
||||
binding.fab.backgroundTintList =
|
||||
ColorStateList.valueOf(resources.getColor(R.color.colorAccent))
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
@ -53,6 +55,7 @@ class SourcesActivity : AppCompatActivity(), DIAware {
|
||||
binding.recyclerView.setHasFixedSize(true)
|
||||
binding.recyclerView.layoutManager = mLayoutManager
|
||||
|
||||
CountingIdlingResourceSingleton.increment()
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
val response = repository.getSourcesDetails()
|
||||
if (response.isNotEmpty()) {
|
||||
@ -71,10 +74,11 @@ class SourcesActivity : AppCompatActivity(), DIAware {
|
||||
Toast.LENGTH_SHORT,
|
||||
).show()
|
||||
}
|
||||
CountingIdlingResourceSingleton.decrement()
|
||||
}
|
||||
|
||||
binding.fab.setOnClickListener {
|
||||
startActivity(Intent(this@SourcesActivity, UpsertSourceActivity::class.java))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package bou.amine.apps.readerforselfossv2.android.testing
|
||||
|
||||
import androidx.test.espresso.idling.CountingIdlingResource
|
||||
|
||||
object CountingIdlingResourceSingleton {
|
||||
|
||||
private const val RESOURCE = "GLOBAL"
|
||||
|
||||
@JvmField
|
||||
val countingIdlingResource = CountingIdlingResource(RESOURCE)
|
||||
|
||||
fun increment() {
|
||||
countingIdlingResource.increment()
|
||||
}
|
||||
|
||||
fun decrement() {
|
||||
if (!countingIdlingResource.isIdleNow) {
|
||||
countingIdlingResource.decrement()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package bou.amine.apps.readerforselfossv2.android.testing
|
||||
|
||||
import android.os.Build
|
||||
|
||||
|
||||
class TestingHelper {
|
||||
fun isUnitTest(): Boolean {
|
||||
var device = Build.DEVICE
|
||||
var product = Build.PRODUCT
|
||||
if (device == null) {
|
||||
device = ""
|
||||
}
|
||||
|
||||
if (product == null) {
|
||||
product = ""
|
||||
}
|
||||
return device == "robolectric" && product == "robolectric"
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user