Skip to content

Commit

Permalink
MBX-2792 unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Akylbek Utekeshev committed Sep 18, 2023
1 parent fc2e3e2 commit af3b7a4
Show file tree
Hide file tree
Showing 45 changed files with 6,417 additions and 1,075 deletions.
136 changes: 116 additions & 20 deletions Mindbox.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion Mindbox/DI/DependencyProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,9 @@ final class DependencyProvider: DependencyContainer {
let sourceFilter = LayersSourceFilterService()
let layersFilterService = LayersFilterService(actionFilter: actionFilter, sourceFilter: sourceFilter)
let sizeFilter = ElementSizeFilterService()
let colorFilter = ElementsColorFilterService()
let positionFilter = ElementsPositionFilterService()
let elementsFilterService = ElementsFilterService(sizeFilter: sizeFilter, positionFilter: positionFilter)
let elementsFilterService = ElementsFilterService(sizeFilter: sizeFilter, positionFilter: positionFilter, colorFilter: colorFilter)
let contentPositionFilterService = ContentPositionFilterService()
let variantsFilterService = VariantFilterService(layersFilter: layersFilterService,
elementsFilter: elementsFilterService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import Foundation

protocol ContentPositionFilterProtocol {
func filter(_ contentPosition: ContentPositionDTO?) throws -> ContentPosition?
func filter(_ contentPosition: ContentPositionDTO?) throws -> ContentPosition
}

final class ContentPositionFilterService: ContentPositionFilterProtocol {
Expand All @@ -20,7 +20,7 @@ final class ContentPositionFilterService: ContentPositionFilterProtocol {
static let defaultContentPosition = ContentPosition(gravity: defaultGravity, margin: defaultMargin)
}

func filter(_ contentPosition: ContentPositionDTO?) throws -> ContentPosition? {
func filter(_ contentPosition: ContentPositionDTO?) throws -> ContentPosition {
guard let contentPosition = contentPosition else {
return Constants.defaultContentPosition
}
Expand Down Expand Up @@ -54,7 +54,7 @@ final class ContentPositionFilterService: ContentPositionFilterProtocol {
}

guard let customMargin = customMargin else {
return nil
throw CustomDecodingError.unknownType("ContentPositionFilterService validation not passed. Inapp will be skipped.")
}

return ContentPosition(gravity: customGravity, margin: customMargin)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// ElementsColorFilterService.swift
// Mindbox
//
// Created by vailence on 15.09.2023.
// Copyright © 2023 Mindbox. All rights reserved.
//

import Foundation

protocol ElementsColorFilterProtocol {
func filter(_ color: String?) throws -> String
}

final class ElementsColorFilterService: ElementsColorFilterProtocol {
enum Constants {
static let defaultColor = "#000000"
}

func filter(_ color: String?) throws -> String {
guard let color = color else {
return Constants.defaultColor
}
return color.isHexValid() ? color : Constants.defaultColor
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
//

import Foundation
import MindboxLogger

protocol ElementsFilterProtocol {
func filter(_ elements: [ContentElementDTO]?) throws -> [ContentElement]?
func filter(_ elements: [ContentElementDTO]?) throws -> [ContentElement]
}

final class ElementsFilterService: ElementsFilterProtocol {
Expand All @@ -21,13 +22,15 @@ final class ElementsFilterService: ElementsFilterProtocol {

private let sizeFilter: ElementsSizeFilterProtocol
private let positionFilter: ElementsPositionFilterProtocol
private let colorFilter: ElementsColorFilterProtocol

init(sizeFilter: ElementsSizeFilterProtocol, positionFilter: ElementsPositionFilterProtocol) {
init(sizeFilter: ElementsSizeFilterProtocol, positionFilter: ElementsPositionFilterProtocol, colorFilter: ElementsColorFilterProtocol) {
self.sizeFilter = sizeFilter
self.positionFilter = positionFilter
self.colorFilter = colorFilter
}

func filter(_ elements: [ContentElementDTO]?) throws -> [ContentElement]? {
func filter(_ elements: [ContentElementDTO]?) throws -> [ContentElement] {
guard let elements = elements, !elements.isEmpty else {
return []
}
Expand All @@ -41,12 +44,10 @@ final class ElementsFilterService: ElementsFilterProtocol {

switch element {
case .closeButton(let closeButtonElementDTO):
guard let size = try sizeFilter.filter(closeButtonElementDTO.size),
let position = try positionFilter.filter(closeButtonElementDTO.position) else {
return nil
}

let customCloseButtonElement = CloseButtonElement(color: closeButtonElementDTO.color?.element ?? Constants.defaultColor,
let size = try sizeFilter.filter(closeButtonElementDTO.size)
let position = try positionFilter.filter(closeButtonElementDTO.position)
let color = try colorFilter.filter(closeButtonElementDTO.color?.element)
let customCloseButtonElement = CloseButtonElement(color: color,
lineWidth: closeButtonElementDTO.lineWidth?.element ?? Constants.lineWidth,
size: size,
position: position)
Expand All @@ -56,7 +57,7 @@ final class ElementsFilterService: ElementsFilterProtocol {
continue elementsLoop
}
}

return filteredElements
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import Foundation

protocol ElementsPositionFilterProtocol {
func filter(_ position: ContentElementPositionDTO?) throws -> ContentElementPosition?
func filter(_ position: ContentElementPositionDTO?) throws -> ContentElementPosition
}

final class ElementsPositionFilterService: ElementsPositionFilterProtocol {
Expand All @@ -19,7 +19,7 @@ final class ElementsPositionFilterService: ElementsPositionFilterProtocol {

}

func filter(_ position: ContentElementPositionDTO?) throws -> ContentElementPosition? {
func filter(_ position: ContentElementPositionDTO?) throws -> ContentElementPosition {
guard let position = position,
let margin = position.margin else {
return ContentElementPosition(margin: Constants.defaultMargin)
Expand Down Expand Up @@ -48,6 +48,6 @@ final class ElementsPositionFilterService: ElementsPositionFilterProtocol {
return ContentElementPosition(margin: Constants.defaultMargin)
}

return nil
throw CustomDecodingError.unknownType("ElementsPositionFilterService validation not passed. In-app will be ignored.")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@
import Foundation

protocol ElementsSizeFilterProtocol {
func filter(_ size: ContentElementSizeDTO?) throws -> ContentElementSize?
func filter(_ size: ContentElementSizeDTO?) throws -> ContentElementSize
}

final class ElementSizeFilterService: ElementsSizeFilterProtocol {
enum Constants {
static let defaultSize = ContentElementSize(kind: .dp, width: 24, height: 24)
}

func filter(_ size: ContentElementSizeDTO?) throws -> ContentElementSize? {
func filter(_ size: ContentElementSizeDTO?) throws -> ContentElementSize {
guard let size = size else {
return Constants.defaultSize
}
Expand All @@ -34,6 +34,6 @@ final class ElementSizeFilterService: ElementsSizeFilterProtocol {
return Constants.defaultSize
}

return nil
throw CustomDecodingError.unknownType("ElementSizeFilterService validation not passed. In-app will be ignored.")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,27 @@ protocol InappFilterProtocol {

final class InappsFilterService: InappFilterProtocol {
private let variantsFilter: VariantFilterProtocol
private let sdkVersionNumeric = 8

init(variantsFilter: VariantFilterProtocol) {
self.variantsFilter = variantsFilter
}

func filter(inapps: [InAppDTO]?) -> [InApp] {
guard let inapps = inapps else {
guard var inapps = inapps else {
Logger.common(message: "Received nil for in-apps. Returning an empty array.", level: .debug, category: .inAppMessages)
return []
}

inapps = filterInappsBySDKVersion(inapps)

Logger.common(message: "Processing \(inapps.count) in-app(s).", level: .debug, category: .inAppMessages)

var filteredInapps: [InApp] = []
for inapp in inapps {
do {
if let variants = try variantsFilter.filter(inapp.form.variants), !variants.isEmpty {
let variants = try variantsFilter.filter(inapp.form.variants)
if !variants.isEmpty {
let formModel = InAppForm(variants: variants)
let inappModel = InApp(id: inapp.id,
sdkVersion: inapp.sdkVersion,
Expand All @@ -40,11 +44,24 @@ final class InappsFilterService: InappFilterProtocol {
filteredInapps.append(inappModel)
}
} catch {
print("Error filtering variants for in-app with id \(inapp.id): \(error.localizedDescription)")
Logger.common(message: "In-app [ID:] \(inapp.id)\n[Error]: \(error)", level: .error, category: .inAppMessages)
}
}

Logger.common(message: "Filtering process completed. \(filteredInapps.count) valid in-app(s) found.", level: .debug, category: .inAppMessages)
return filteredInapps
}

func filterInappsBySDKVersion(_ inapps: [InAppDTO]) -> [InAppDTO] {
let inapps = inapps

let filteredInapps = inapps.filter {
let minVersionValid = $0.sdkVersion.min.map { $0 <= sdkVersionNumeric } ?? false
let maxVersionValid = $0.sdkVersion.max.map { $0 >= sdkVersionNumeric } ?? true

return minVersionValid && maxVersionValid
}

return filteredInapps
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@
import Foundation

protocol LayerActionFilterProtocol {
func filter(_ action: ContentBackgroundLayerActionDTO?) throws -> ContentBackgroundLayerAction?
func filter(_ action: ContentBackgroundLayerActionDTO?) throws -> ContentBackgroundLayerAction
}

final class LayerActionFilterService: LayerActionFilterProtocol {
func filter(_ action: ContentBackgroundLayerActionDTO?) throws -> ContentBackgroundLayerAction? {
func filter(_ action: ContentBackgroundLayerActionDTO?) throws -> ContentBackgroundLayerAction {
guard let action = action,
action.actionType != .unknown else {
return nil
throw CustomDecodingError.unknownType("LayerActionFilterService validation not passed.")
}

switch action {
Expand All @@ -29,6 +29,6 @@ final class LayerActionFilterService: LayerActionFilterProtocol {
break
}

return nil
throw CustomDecodingError.unknownType("LayerActionFilterService validation not passed.")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Foundation
import MindboxLogger

protocol LayersFilterProtocol {
func filter(_ layers: [ContentBackgroundLayerDTO]?) throws -> [ContentBackgroundLayer]?
func filter(_ layers: [ContentBackgroundLayerDTO]?) throws -> [ContentBackgroundLayer]
}

final class LayersFilterService: LayersFilterProtocol {
Expand All @@ -22,24 +22,21 @@ final class LayersFilterService: LayersFilterProtocol {
self.sourceFilter = sourceFilter
}

func filter(_ layers: [ContentBackgroundLayerDTO]?) throws -> [ContentBackgroundLayer]? {
func filter(_ layers: [ContentBackgroundLayerDTO]?) throws -> [ContentBackgroundLayer] {
var filteredLayers: [ContentBackgroundLayer] = []

guard let layers = layers else {
return nil
throw CustomDecodingError.unknownType("LayersFilterService validation not passed.")
}

for layer in layers {
switch layer {
case .image(let imageContentBackgroundLayerDTO):
if let action = try actionFilter.filter(imageContentBackgroundLayerDTO.action),
let source = try sourceFilter.filter(imageContentBackgroundLayerDTO.source) {
let imageLayer = ImageContentBackgroundLayer(action: action, source: source)
let newLayer = try ContentBackgroundLayer(type: layer.layerType, imageLayer: imageLayer)
filteredLayers.append(newLayer)
} else {
return []
}
let action = try actionFilter.filter(imageContentBackgroundLayerDTO.action)
let source = try sourceFilter.filter(imageContentBackgroundLayerDTO.source)
let imageLayer = ImageContentBackgroundLayer(action: action, source: source)
let newLayer = try ContentBackgroundLayer(type: layer.layerType, imageLayer: imageLayer)
filteredLayers.append(newLayer)
case .unknown:
break
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,26 @@
import Foundation

protocol LayersSourceFilterProtocol {
func filter(_ source: ContentBackgroundLayerSourceDTO?) throws -> ContentBackgroundLayerSource?
func filter(_ source: ContentBackgroundLayerSourceDTO?) throws -> ContentBackgroundLayerSource
}

final class LayersSourceFilterService: LayersSourceFilterProtocol {
func filter(_ source: ContentBackgroundLayerSourceDTO?) throws -> ContentBackgroundLayerSource? {
func filter(_ source: ContentBackgroundLayerSourceDTO?) throws -> ContentBackgroundLayerSource {
guard let source = source,
source.sourceType != .unknown else {
return nil
throw CustomDecodingError.unknownType("LayersSourceFilterService validation not passed.")
}

switch source {
case .url(let urlLayerSource):
if let value = urlLayerSource.value {
if let value = urlLayerSource.value, !value.isEmpty {
let urlLayerSourceModel = UrlLayerSource(value: value)
return try ContentBackgroundLayerSource(type: .url, urlModel: urlLayerSourceModel)
}
case .unknown:
break
}

return nil
throw CustomDecodingError.unknownType("LayersSourceFilterService validation not passed.")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import Foundation

protocol VariantFilterProtocol {
func filter(_ variants: [MindboxFormVariantDTO]?) throws -> [MindboxFormVariant]?
func filter(_ variants: [MindboxFormVariantDTO]?) throws -> [MindboxFormVariant]
}

final class VariantFilterService: VariantFilterProtocol {
Expand All @@ -24,24 +24,25 @@ final class VariantFilterService: VariantFilterProtocol {
self.contentPositionFilter = contentPositionFilter
}

func filter(_ variants: [MindboxFormVariantDTO]?) throws -> [MindboxFormVariant]? {
func filter(_ variants: [MindboxFormVariantDTO]?) throws -> [MindboxFormVariant] {
var resultVariants: [MindboxFormVariant] = []
guard let variants = variants else {
return nil
throw CustomDecodingError.unknownType("VariantFilterService validation not passed.")
}

variantsLoop: for variant in variants {
switch variant {
case .modal(let modalFormVariantDTO):
guard let content = modalFormVariantDTO.content,
let background = content.background else {
return nil
throw CustomDecodingError.unknownType("VariantFilterService validation not passed.")
}

guard let filteredLayers = try layersFilter.filter(background.layers),
let fileterdElements = try elementsFilter.filter(content.elements) else {
return nil
let filteredLayers = try layersFilter.filter(background.layers)
if filteredLayers.isEmpty {
continue variantsLoop
}
let fileterdElements = try elementsFilter.filter(content.elements)

let backgroundModel = ContentBackground(layers: filteredLayers)

Expand All @@ -52,14 +53,12 @@ final class VariantFilterService: VariantFilterProtocol {
case .snackbar(let snackbarFormVariant):
guard let content = snackbarFormVariant.content,
let background = content.background else {
return nil
throw CustomDecodingError.unknownType("VariantFilterService validation not passed.")
}

guard let filteredLayers = try layersFilter.filter(background.layers),
let filteredElements = try elementsFilter.filter(content.elements),
let contentPosition = try contentPositionFilter.filter(content.position) else {
return nil
}
let filteredLayers = try layersFilter.filter(background.layers)
let filteredElements = try elementsFilter.filter(content.elements)
let contentPosition = try contentPositionFilter.filter(content.position)

let backgroundModel = ContentBackground(layers: filteredLayers)
let contentModel = SnackbarFormVariantContent(background: backgroundModel,
Expand Down
Loading

0 comments on commit af3b7a4

Please sign in to comment.