Coverage Summary for Class: TrackingIdsResolverImpl (cloud.mindbox.mobile_sdk.managers)

Class Method, % Branch, % Line, % Instruction, %
TrackingIdsResolverImpl 100% (6/6) 100% (6/6) 100% (25/25) 100% (196/196)
TrackingIdsResolverImpl$1 0% (0/1) 0% (0/1) 0% (0/2)
TrackingIdsResolverImpl$2 0% (0/1) 0% (0/1) 0% (0/2)
TrackingIdsResolverImpl$lastSent$1 100% (1/1) 75% (6/8) 100% (4/4) 95.7% (45/47)
TrackingIdsResolverImpl$markSent$1 100% (1/1) 100% (2/2) 100% (2/2) 100% (39/39)
TrackingIdsResolverImpl$markSent$1$1 100% (1/1) 100% (1/1) 100% (3/3)
TrackingIdsResolverImpl$mergeWithLastSent$$inlined$sortedBy$1 0% (0/1)
TrackingIdsResolverImpl$mergeWithLastSent$1 100% (1/1) 100% (1/1) 100% (3/3)
TrackingIdsResolverImpl$resolve$1
TrackingIdsResolverImpl$resolve$reading$1 100% (1/1) 100% (1/1) 100% (16/16)
TrackingIdsResolverImpl$resolve$results$1 100% (1/1) 100% (1/1) 100% (20/20)
Total 80% (12/15) 87.5% (14/16) 94.6% (35/37) 98.2% (322/328)


 package cloud.mindbox.mobile_sdk.managers
 
 import android.content.Context
 import cloud.mindbox.mobile_sdk.Mindbox
 import cloud.mindbox.mobile_sdk.logger.mindboxLogI
 import cloud.mindbox.mobile_sdk.models.TrackingId
 import cloud.mindbox.mobile_sdk.pushes.PushServiceHandler
 import cloud.mindbox.mobile_sdk.pushes.TrackingIdResult
 import cloud.mindbox.mobile_sdk.repository.MindboxPreferences
 import cloud.mindbox.mobile_sdk.utils.loggingRunCatching
 import com.google.gson.Gson
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.async
 import kotlinx.coroutines.withTimeoutOrNull
 import kotlin.time.Duration.Companion.milliseconds
 
 private const val READ_TRACKING_IDS_TIMEOUT = 5000L
 
 internal interface TrackingIdsResolver {
 
     suspend fun resolve(context: Context): List<TrackingId>
 
     fun hasChanged(trackingIds: List<TrackingId>): Boolean
 
     fun markSent(trackingIds: List<TrackingId>)
 }
 
 internal class TrackingIdsResolverImpl(
     private val pushServiceHandlers: () -> List<PushServiceHandler> = { Mindbox.pushServiceHandlers },
     private val scope: () -> CoroutineScope = { Mindbox.mindboxScope },
     private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO,
     private val timeoutMillis: Long = READ_TRACKING_IDS_TIMEOUT,
 ) : TrackingIdsResolver {
 
     private val gson = Gson()
 
     override suspend fun resolve(context: Context): List<TrackingId> {
         if (!MindboxPreferences.shouldCollectTrackingIds) return emptyList()
 
         val reading = scope().async(ioDispatcher) {
             pushServiceHandlers().map { handler -> handler.tryGetTrackingId(context) }
         }
         val results = withTimeoutOrNull(timeoutMillis.milliseconds) { reading.await() }
         if (results == null) {
             reading.cancel()
             mindboxLogI("Timed out reading tracking id providers, repeating the last reported set")
             return lastSent()
         }
 
         return results.mergeWithLastSent()
     }
 
     override fun hasChanged(trackingIds: List<TrackingId>): Boolean = trackingIds != lastSent()
 
     override fun markSent(trackingIds: List<TrackingId>): Unit = loggingRunCatching {
         MindboxPreferences.lastSentTrackingIds = gson.toJson(trackingIds)
         mindboxLogI("Sent tracking ids: ${trackingIds.joinToString { it.type }.ifEmpty { "none" }}")
     }
 
     private fun lastSent(): List<TrackingId> = loggingRunCatching(defaultValue = emptyList()) {
         MindboxPreferences.lastSentTrackingIds
             .takeIf { it.isNotBlank() }
             ?.let { gson.fromJson(it, Array<TrackingId>::class.java)?.toList() }
             ?: emptyList()
     }
 
     private fun List<TrackingIdResult>.mergeWithLastSent(): List<TrackingId> {
         val fresh = filterIsInstance<TrackingIdResult.Success>().map { it.trackingId }
         val answered = fresh.map { it.type }.toSet() +
             filterIsInstance<TrackingIdResult.Denied>().map { it.type }
 
         val kept = lastSent().filterNot { it.type in answered }
         if (kept.isNotEmpty()) {
             mindboxLogI("Keeping tracking ids we could not read: ${kept.joinToString { it.type }}")
         }
 
         return (fresh + kept)
             .sortedBy { it.type }
             .distinctBy { it.type }
     }
 }