Coverage Summary for Class: TreeTargeting (cloud.mindbox.mobile_sdk.inapp.domain.models)

Class Method, % Branch, % Line, % Instruction, %
TreeTargeting 100% (1/1) 100% (1/1) 100% (9/9)
TreeTargeting$CityNode 62.5% (5/8) 100% (6/6) 80% (12/15) 96.6% (84/87)
TreeTargeting$CityNode$inAppGeoRepositoryImpl$2 100% (1/1) 100% (1/1) 100% (2/2)
TreeTargeting$CountryNode 62.5% (5/8) 100% (6/6) 80% (12/15) 96.6% (84/87)
TreeTargeting$CountryNode$inAppGeoRepositoryImpl$2 100% (1/1) 100% (1/1) 100% (2/2)
TreeTargeting$IntersectionNode 62.5% (5/8) 33.3% (6/18) 53.8% (14/26) 66.4% (95/143)
TreeTargeting$IntersectionNode$fetchTargetingInfo$1
TreeTargeting$IntersectionNode$getOperationsSet$1
TreeTargeting$PushPermissionNode 37.5% (3/8) 100% (2/2) 44.4% (4/9) 90.6% (48/53)
TreeTargeting$PushPermissionNode$permissionManager$2 100% (1/1) 100% (1/1) 100% (2/2)
TreeTargeting$RegionNode 87.5% (7/8) 100% (6/6) 94.4% (17/18) 98.9% (86/87)
TreeTargeting$RegionNode$inAppGeoRepositoryImpl$2 100% (1/1) 100% (1/1) 100% (2/2)
TreeTargeting$SegmentNode 87.5% (7/8) 95% (19/20) 95% (19/20) 99.4% (168/169)
TreeTargeting$SegmentNode$inAppSegmentationRepository$2 100% (1/1) 100% (1/1) 100% (2/2)
TreeTargeting$SegmentNode$WhenMappings
TreeTargeting$TrueNode 100% (7/7) 100% (7/7) 100% (15/15)
TreeTargeting$UnionNode 87.5% (7/8) 66.7% (12/18) 88% (22/25) 88.1% (133/151)
TreeTargeting$UnionNode$fetchTargetingInfo$1
TreeTargeting$UnionNode$getOperationsSet$1
TreeTargeting$VisitNode 28.6% (2/7) 100% (10/10) 66.7% (10/15) 93% (66/71)
TreeTargeting$VisitNode$WhenMappings
Total 71.1% (54/76) 77.9% (67/86) 78.8% (123/156) 90.5% (798/882)


 package cloud.mindbox.mobile_sdk.inapp.domain.models
 
 import cloud.mindbox.mobile_sdk.di.mindboxInject
 import cloud.mindbox.mobile_sdk.inapp.domain.interfaces.PermissionManager
 import cloud.mindbox.mobile_sdk.logger.mindboxLogD
 import cloud.mindbox.mobile_sdk.repository.MindboxPreferences
 
 internal interface ITargeting {
     fun checkTargeting(data: TargetingData): Boolean
 }
 
 internal sealed interface TargetingData {
     interface OperationName : TargetingData {
         val triggerEventName: String
     }
 
     interface OperationBody : TargetingData {
         val operationBody: String?
     }
 }
 
 internal interface TargetingInfo {
     suspend fun fetchTargetingInfo(data: TargetingData)
 
     fun hasSegmentationNode(): Boolean
 
     fun hasGeoNode(): Boolean
 
     fun hasOperationNode(): Boolean
 
     fun hasProductSegmentationNode(): Boolean = false
 
     suspend fun getOperationsSet(): Set<String>
 }
 
 internal enum class Kind {
     POSITIVE,
     NEGATIVE
 }
 
 internal enum class KindVisit {
     GTE,
     LTE,
     EQUALS,
     NOT_EQUALS
 }
 
 internal enum class KindAny {
     ANY,
     NONE,
 }
 
 internal enum class KindSubstring {
     SUBSTRING,
     NOT_SUBSTRING,
     STARTS_WITH,
     ENDS_WITH
 }
 
 internal sealed class TreeTargeting(open val type: String) :
     ITargeting, TargetingInfo {
 
     internal data class TrueNode(override val type: String) : TreeTargeting(type) {
 
         override fun checkTargeting(data: TargetingData): Boolean {
             return true
         }
 
         override suspend fun fetchTargetingInfo(data: TargetingData) {
             return
         }
 
         override fun hasSegmentationNode(): Boolean {
             return false
         }
 
         override fun hasGeoNode(): Boolean {
             return false
         }
 
         override fun hasOperationNode(): Boolean {
             return false
         }
 
         override suspend fun getOperationsSet(): Set<String> {
             return emptySet()
         }
     }
 
     internal data class CountryNode(
         override val type: String,
         val kind: Kind,
         val ids: List<String>,
     ) : TreeTargeting(type) {
 
         private val inAppGeoRepositoryImpl by mindboxInject { inAppGeoRepository }
 
         override fun checkTargeting(data: TargetingData): Boolean {
             if (inAppGeoRepositoryImpl.getGeoFetchedStatus() != GeoFetchStatus.GEO_FETCH_SUCCESS) return false
             val countryId = inAppGeoRepositoryImpl.getGeo().countryId
             return if (kind == Kind.POSITIVE) ids.contains(countryId) else ids.contains(countryId).not()
         }
 
         override suspend fun getOperationsSet(): Set<String> = emptySet()
 
         override suspend fun fetchTargetingInfo(data: TargetingData) {
             if (inAppGeoRepositoryImpl.getGeoFetchedStatus() == GeoFetchStatus.GEO_NOT_FETCHED) {
                 inAppGeoRepositoryImpl.fetchGeo()
             }
         }
 
         override fun hasSegmentationNode(): Boolean = false
 
         override fun hasGeoNode(): Boolean = true
 
         override fun hasOperationNode(): Boolean = false
     }
 
     internal data class CityNode(
         override val type: String,
         val kind: Kind,
         val ids: List<String>,
     ) : TreeTargeting(type) {
 
         private val inAppGeoRepositoryImpl by mindboxInject { inAppGeoRepository }
 
         override fun checkTargeting(data: TargetingData): Boolean {
             if (inAppGeoRepositoryImpl.getGeoFetchedStatus() != GeoFetchStatus.GEO_FETCH_SUCCESS) return false
             val cityId = inAppGeoRepositoryImpl.getGeo().cityId
             return if (kind == Kind.POSITIVE) ids.contains(cityId) else ids.contains(cityId).not()
         }
 
         override suspend fun getOperationsSet(): Set<String> = emptySet()
 
         override suspend fun fetchTargetingInfo(data: TargetingData) {
             if (inAppGeoRepositoryImpl.getGeoFetchedStatus() == GeoFetchStatus.GEO_NOT_FETCHED) {
                 inAppGeoRepositoryImpl.fetchGeo()
             }
         }
 
         override fun hasSegmentationNode(): Boolean = false
 
         override fun hasGeoNode(): Boolean = true
 
         override fun hasOperationNode(): Boolean = false
     }
 
     internal data class RegionNode(
         override val type: String,
         val kind: Kind,
         val ids: List<String>,
     ) : TreeTargeting(type) {
 
         private val inAppGeoRepositoryImpl by mindboxInject { inAppGeoRepository }
 
         override fun checkTargeting(data: TargetingData): Boolean {
             if (inAppGeoRepositoryImpl.getGeoFetchedStatus() != GeoFetchStatus.GEO_FETCH_SUCCESS) return false
             val regionId = inAppGeoRepositoryImpl.getGeo().regionId
             return if (kind == Kind.POSITIVE) {
                 ids.contains(regionId)
             } else {
                 ids
                     .contains(regionId)
                     .not()
             }
         }
 
         override suspend fun getOperationsSet(): Set<String> {
             return emptySet()
         }
 
         override suspend fun fetchTargetingInfo(data: TargetingData) {
             if (inAppGeoRepositoryImpl.getGeoFetchedStatus() == GeoFetchStatus.GEO_NOT_FETCHED) {
                 inAppGeoRepositoryImpl.fetchGeo()
             }
         }
 
         override fun hasSegmentationNode(): Boolean {
             return false
         }
 
         override fun hasGeoNode(): Boolean {
             return true
         }
 
         override fun hasOperationNode(): Boolean {
             return false
         }
     }
 
     internal data class IntersectionNode(
         override val type: String,
         val nodes: List<TreeTargeting>,
     ) : TreeTargeting(type) {
         override fun checkTargeting(data: TargetingData): Boolean {
             var rez = true
             for (node in nodes) {
                 if (node.checkTargeting(data).not()) {
                     rez = false
                 }
             }
             return rez
         }
 
         override suspend fun getOperationsSet(): Set<String> {
             return nodes.flatMap { treeTargeting ->
                 treeTargeting.getOperationsSet()
             }.toSet()
         }
 
         override suspend fun fetchTargetingInfo(data: TargetingData) {
             for (node in nodes) {
                 node.fetchTargetingInfo(data)
             }
         }
 
         override fun hasSegmentationNode(): Boolean {
             for (node in nodes) {
                 if (node.hasSegmentationNode()) {
                     return true
                 }
             }
             return false
         }
 
         override fun hasGeoNode(): Boolean {
             for (node in nodes) {
                 if (node.hasGeoNode()) {
                     return true
                 }
             }
             return false
         }
 
         override fun hasOperationNode(): Boolean {
             for (node in nodes) {
                 if (node.hasOperationNode()) {
                     return true
                 }
             }
             return false
         }
 
         override fun hasProductSegmentationNode() = nodes.any { it.hasProductSegmentationNode() }
     }
 
     internal data class UnionNode(
         override val type: String,
         val nodes: List<TreeTargeting>,
     ) : TreeTargeting(type) {
         override fun checkTargeting(data: TargetingData): Boolean {
             var rez = false
             for (node in nodes) {
                 val check = node.checkTargeting(data)
                 mindboxLogD("Check UnionNode ${node.type}: $check")
                 if (check) {
                     rez = true
                 }
             }
             return rez
         }
 
         override suspend fun getOperationsSet(): Set<String> {
             return nodes.flatMap { treeTargeting ->
                 treeTargeting.getOperationsSet()
             }.toSet()
         }
 
         override suspend fun fetchTargetingInfo(data: TargetingData) {
             for (node in nodes) {
                 node.fetchTargetingInfo(data)
             }
         }
 
         override fun hasSegmentationNode(): Boolean {
             for (node in nodes) {
                 if (node.hasSegmentationNode()) return true
             }
             return false
         }
 
         override fun hasGeoNode(): Boolean {
             for (node in nodes) {
                 if (node.hasGeoNode()) return true
             }
             return false
         }
 
         override fun hasOperationNode(): Boolean {
             for (node in nodes) {
                 if (node.hasOperationNode()) return true
             }
             return false
         }
 
         override fun hasProductSegmentationNode() = nodes.any { it.hasProductSegmentationNode() }
     }
 
     internal data class SegmentNode(
         override val type: String,
         val kind: Kind,
         val segmentationExternalId: String,
         val segmentExternalId: String,
     ) : TreeTargeting(type) {
 
         private val inAppSegmentationRepository by mindboxInject { inAppSegmentationRepository }
 
         override fun checkTargeting(data: TargetingData): Boolean {
             if (inAppSegmentationRepository.getCustomerSegmentationFetched() != CustomerSegmentationFetchStatus.SEGMENTATION_FETCH_SUCCESS) return false
             val segmentationsWrapperList = inAppSegmentationRepository.getCustomerSegmentations()
             return when (kind) {
                 Kind.POSITIVE -> segmentationsWrapperList.find { segmentationWrapper -> segmentationWrapper.segmentation == segmentationExternalId }?.segment == segmentExternalId
                 Kind.NEGATIVE -> segmentationsWrapperList.find { it.segmentation == segmentationExternalId }
                     ?.segment
                     ?.let { it != segmentExternalId } == true
             }
         }
 
         override suspend fun getOperationsSet(): Set<String> = emptySet()
 
         override suspend fun fetchTargetingInfo(data: TargetingData) {
             if (inAppSegmentationRepository.getCustomerSegmentationFetched() == CustomerSegmentationFetchStatus.SEGMENTATION_NOT_FETCHED) {
                 inAppSegmentationRepository.fetchCustomerSegmentations()
             }
         }
 
         override fun hasSegmentationNode(): Boolean = true
 
         override fun hasGeoNode(): Boolean = false
 
         override fun hasOperationNode(): Boolean = false
     }
 
     internal data class VisitNode(
         override val type: String,
         val kind: KindVisit,
         val value: Long
     ) : TreeTargeting(type) {
         override fun checkTargeting(data: TargetingData): Boolean {
             val userVisitCount = MindboxPreferences.userVisitCount.toLong()
             return when (kind) {
                 KindVisit.GTE -> {
                     userVisitCount >= value
                 }
 
                 KindVisit.LTE -> {
                     userVisitCount <= value
                 }
 
                 KindVisit.EQUALS -> {
                     value == userVisitCount
                 }
 
                 KindVisit.NOT_EQUALS -> {
                     value != userVisitCount
                 }
             }
         }
 
         override suspend fun fetchTargetingInfo(data: TargetingData) {
             return
         }
 
         override fun hasSegmentationNode(): Boolean {
             return false
         }
 
         override fun hasGeoNode(): Boolean {
             return false
         }
 
         override fun hasOperationNode(): Boolean {
             return false
         }
 
         override suspend fun getOperationsSet(): Set<String> {
             return emptySet()
         }
     }
 
     internal data class PushPermissionNode(override val type: String, val value: Boolean) : TreeTargeting(type) {
 
         private val permissionManager: PermissionManager by mindboxInject { permissionManager }
 
         override fun checkTargeting(data: TargetingData): Boolean = permissionManager.isNotificationEnabled() == value
 
         override suspend fun fetchTargetingInfo(data: TargetingData) {
             return
         }
 
         override fun hasSegmentationNode(): Boolean = false
 
         override fun hasGeoNode(): Boolean = false
 
         override fun hasOperationNode(): Boolean = false
 
         override suspend fun getOperationsSet(): Set<String> = emptySet()
     }
 }