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()
}
}