diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1b49d9cd..5547f9a6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,7 @@ jobs: build: runs-on: macos-13 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4 - name: Update bundler run: gem install bundler - name: Install bundler dependencies diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 8140dcc3..7c7e0bbd 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -12,7 +12,7 @@ jobs: unit: runs-on: macos-13 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4 - name: Update bundler run: gem install bundler - name: Install bundler dependencies @@ -22,9 +22,9 @@ jobs: publish: needs: [unit] - runs-on: macos-11 + runs-on: macos-13 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4 - name: Release generation run: ./git-release.sh "${{ github.event.head_commit.message }}" "${{secrets.GITHUBACCESSTOKEN}}" "${{secrets.GITHUBUSER}}" - name: Update bundler diff --git a/Gemfile.lock b/Gemfile.lock index a60d0cd6..fac16515 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -9,7 +9,7 @@ GEM minitest (>= 5.1) tzinfo (~> 2.0) zeitwerk (~> 2.3) - addressable (2.8.4) + addressable (2.8.5) public_suffix (>= 2.0.2, < 6.0) algoliasearch (1.27.5) httpclient (~> 2.8, >= 2.8.3) @@ -17,8 +17,8 @@ GEM artifactory (3.0.15) atomos (0.1.3) aws-eventstream (1.2.0) - aws-partitions (1.786.0) - aws-sdk-core (3.178.0) + aws-partitions (1.825.0) + aws-sdk-core (3.182.0) aws-eventstream (~> 1, >= 1.0.2) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.5) @@ -26,8 +26,8 @@ GEM aws-sdk-kms (1.71.0) aws-sdk-core (~> 3, >= 3.177.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.130.0) - aws-sdk-core (~> 3, >= 3.177.0) + aws-sdk-s3 (1.134.0) + aws-sdk-core (~> 3, >= 3.181.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.6) aws-sigv4 (1.6.0) @@ -86,7 +86,7 @@ GEM escape (0.0.4) ethon (0.16.0) ffi (>= 1.15.0) - excon (0.100.0) + excon (0.103.0) faraday (1.10.3) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) @@ -159,9 +159,9 @@ GEM fourflusher (2.3.1) fuzzy_match (2.0.4) gh_inspector (1.1.3) - google-apis-androidpublisher_v3 (0.45.0) + google-apis-androidpublisher_v3 (0.49.0) google-apis-core (>= 0.11.0, < 2.a) - google-apis-core (0.11.0) + google-apis-core (0.11.1) addressable (~> 2.5, >= 2.5.1) googleauth (>= 0.16.2, < 2.a) httpclient (>= 2.8.1, < 3.a) @@ -190,10 +190,9 @@ GEM google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) - googleauth (1.6.0) + googleauth (1.8.0) faraday (>= 0.17.3, < 3.a) jwt (>= 1.4, < 3.0) - memoist (~> 0.16) multi_json (~> 1.11) os (>= 0.9, < 2.0) signet (>= 0.16, < 2.a) @@ -206,9 +205,8 @@ GEM jmespath (1.6.2) json (2.6.3) jwt (2.7.1) - memoist (0.16.2) mini_magick (4.12.0) - mini_mime (1.1.2) + mini_mime (1.1.5) minitest (5.18.0) molinillo (0.8.0) multi_json (1.15.0) @@ -227,13 +225,13 @@ GEM trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) retriable (3.1.2) - rexml (3.2.5) + rexml (3.2.6) rouge (2.0.7) ruby-macho (2.5.1) ruby2_keywords (0.0.5) rubyzip (2.3.2) security (0.1.3) - signet (0.17.0) + signet (0.18.0) addressable (~> 2.8) faraday (>= 0.17.5, < 3.a) jwt (>= 1.5, < 3.0) diff --git a/Mindbox.podspec b/Mindbox.podspec index d95d9ab5..f9274af9 100644 --- a/Mindbox.podspec +++ b/Mindbox.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = "Mindbox" - spec.version = "2.8.0-rc" + spec.version = "2.8.0" spec.summary = "SDK for integration with Mindbox" spec.description = "This library allows you to integrate data transfer to Mindbox Marketing Cloud" spec.homepage = "https://github.com/mindbox-cloud/ios-sdk" diff --git a/Mindbox.xcodeproj/project.pbxproj b/Mindbox.xcodeproj/project.pbxproj index 5191695b..ef95b3b6 100644 --- a/Mindbox.xcodeproj/project.pbxproj +++ b/Mindbox.xcodeproj/project.pbxproj @@ -312,17 +312,13 @@ F331DCC12A80993600222120 /* ContentElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DC9B2A80993600222120 /* ContentElement.swift */; }; F331DCC32A80993600222120 /* ContentElementPosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DC9F2A80993600222120 /* ContentElementPosition.swift */; }; F331DCC42A80993600222120 /* ContentElementPositionMargin.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCA12A80993600222120 /* ContentElementPositionMargin.swift */; }; - F331DCC52A80993600222120 /* PositionMarginKind.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCA32A80993600222120 /* PositionMarginKind.swift */; }; - F331DCC62A80993600222120 /* ContentElementPositionMarginValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCA42A80993600222120 /* ContentElementPositionMarginValidator.swift */; }; F331DCC82A80993600222120 /* ContentBackgroundLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCA82A80993600222120 /* ContentBackgroundLayer.swift */; }; F331DCCB2A80993600222120 /* ContentBackgroundLayerAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCAD2A80993600222120 /* ContentBackgroundLayerAction.swift */; }; F331DCCC2A80993600222120 /* ContentBackgroundLayerSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCAF2A80993600222120 /* ContentBackgroundLayerSource.swift */; }; F331DCD12A80993600222120 /* ContentBackground.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCB62A80993600222120 /* ContentBackground.swift */; }; F331DCD22A80993600222120 /* InappFormVariantContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCB72A80993600222120 /* InappFormVariantContent.swift */; }; F331DCD32A80993600222120 /* InappForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCB82A80993600222120 /* InappForm.swift */; }; - F331DCD42A80993600222120 /* InappValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCB92A80993600222120 /* InappValidator.swift */; }; F331DCD52A80993600222120 /* InAppModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCBA2A80993600222120 /* InAppModel.swift */; }; - F331DCE22A80B4C800222120 /* ContentElementPositionMarginValidatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCE12A80B4C800222120 /* ContentElementPositionMarginValidatorTests.swift */; }; F331DD012A83A56500222120 /* InAppPresentationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCEA2A83A56500222120 /* InAppPresentationManager.swift */; }; F331DD022A83A56500222120 /* PresentationDisplayUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCEE2A83A56500222120 /* PresentationDisplayUseCase.swift */; }; F331DD032A83A56500222120 /* ModalPresentationStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCF02A83A56500222120 /* ModalPresentationStrategy.swift */; }; @@ -346,13 +342,11 @@ F331DD2E2A84CA8900222120 /* UrlLayerSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DD2D2A84CA8900222120 /* UrlLayerSource.swift */; }; F331DD312A84CCA800222120 /* CloseButtonElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DD302A84CCA800222120 /* CloseButtonElement.swift */; }; F331DD332A84D57800222120 /* VariantImageUrlExtractorService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DD322A84D57800222120 /* VariantImageUrlExtractorService.swift */; }; - F331DD582A8648DB00222120 /* ContentElementSizeValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DD572A8648DB00222120 /* ContentElementSizeValidator.swift */; }; F336080D2A8A142800C7C9B7 /* SnackbarFormVariant.swift in Sources */ = {isa = PBXBuildFile; fileRef = F336080C2A8A142800C7C9B7 /* SnackbarFormVariant.swift */; }; F336080F2A8A14D800C7C9B7 /* SnackbarFormVariantContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = F336080E2A8A14D800C7C9B7 /* SnackbarFormVariantContent.swift */; }; F33608122A8A151C00C7C9B7 /* ContentPosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = F33608112A8A151C00C7C9B7 /* ContentPosition.swift */; }; F33608152A8A156900C7C9B7 /* ContentPositionGravity.swift in Sources */ = {isa = PBXBuildFile; fileRef = F33608142A8A156900C7C9B7 /* ContentPositionGravity.swift */; }; F33608182A8A161200C7C9B7 /* ContentPositionMargin.swift in Sources */ = {isa = PBXBuildFile; fileRef = F33608172A8A161200C7C9B7 /* ContentPositionMargin.swift */; }; - F336081A2A8A163D00C7C9B7 /* ContentPositionMarginValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F33608192A8A163D00C7C9B7 /* ContentPositionMarginValidator.swift */; }; F336081C2A8B9EA800C7C9B7 /* SnackbarViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = F336081B2A8B9EA800C7C9B7 /* SnackbarViewFactory.swift */; }; F33608262A8CC94A00C7C9B7 /* SnackbarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F33608252A8CC94A00C7C9B7 /* SnackbarViewController.swift */; }; F33608282A8CD17E00C7C9B7 /* SnackbarPresentationStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = F33608272A8CD17E00C7C9B7 /* SnackbarPresentationStrategy.swift */; }; @@ -367,6 +361,33 @@ F3482F232A65DC37002A41EC /* InAppMessagesDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3482F222A65DC37002A41EC /* InAppMessagesDelegate.swift */; }; F3482F2A2A65DCFC002A41EC /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3482F292A65DCFC002A41EC /* String+Extensions.swift */; }; F37613E12A6A8CFF009F2EE4 /* UIColor+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F37613E02A6A8CFF009F2EE4 /* UIColor+Extensions.swift */; }; + F39116EE2AA53EE400852298 /* VariantImageUrlExtractorServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39116ED2AA53EE400852298 /* VariantImageUrlExtractorServiceTests.swift */; }; + F39116F52AA9AF7A00852298 /* InappFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39116F42AA9AF7A00852298 /* InappFilter.swift */; }; + F39116F82AA9B04E00852298 /* VariantsFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39116F72AA9B04E00852298 /* VariantsFilter.swift */; }; + F39116FA2AA9B32E00852298 /* LayersFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39116F92AA9B32E00852298 /* LayersFilter.swift */; }; + F39116FC2AA9B4A200852298 /* LayerActionFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39116FB2AA9B4A200852298 /* LayerActionFilter.swift */; }; + F39116FE2AA9B54B00852298 /* LayersSourceFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39116FD2AA9B54B00852298 /* LayersSourceFilter.swift */; }; + F39117012AA9B68B00852298 /* ElementsFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39117002AA9B68B00852298 /* ElementsFilter.swift */; }; + F39117032AA9B79100852298 /* ElementsSizeFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39117022AA9B79100852298 /* ElementsSizeFilter.swift */; }; + F39117052AA9B92500852298 /* ElementsPositionFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39117042AA9B92500852298 /* ElementsPositionFilter.swift */; }; + F39117072AA9C69A00852298 /* ContentPositionFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39117062AA9C69A00852298 /* ContentPositionFilter.swift */; }; + F391170B2AB2E74F00852298 /* InappFilterServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F391170A2AB2E74F00852298 /* InappFilterServiceTests.swift */; }; + F391170F2AB4B31800852298 /* unknownVariantType.json in Resources */ = {isa = PBXBuildFile; fileRef = F391170E2AB4B31800852298 /* unknownVariantType.json */; }; + F39117112AB4BD4500852298 /* missingBackgroundSection.json in Resources */ = {isa = PBXBuildFile; fileRef = F39117102AB4BD4500852298 /* missingBackgroundSection.json */; }; + F39117132AB4BD8500852298 /* emptyLayersSection.json in Resources */ = {isa = PBXBuildFile; fileRef = F39117122AB4BD8500852298 /* emptyLayersSection.json */; }; + F39117152AB4BEB900852298 /* unknownLayerType.json in Resources */ = {isa = PBXBuildFile; fileRef = F39117142AB4BEB900852298 /* unknownLayerType.json */; }; + F39117172AB4BF2700852298 /* knownImageUnknownPictureLayerType.json in Resources */ = {isa = PBXBuildFile; fileRef = F39117162AB4BF2700852298 /* knownImageUnknownPictureLayerType.json */; }; + F39117192AB4C02500852298 /* unknownActionLayerType.json in Resources */ = {isa = PBXBuildFile; fileRef = F39117182AB4C02500852298 /* unknownActionLayerType.json */; }; + F391171B2AB4C07900852298 /* redirectUrlValueNumberInsteadOfString.json in Resources */ = {isa = PBXBuildFile; fileRef = F391171A2AB4C07900852298 /* redirectUrlValueNumberInsteadOfString.json */; }; + F391171D2AB4C0BE00852298 /* missingIntentPayloadInActionLayer.json in Resources */ = {isa = PBXBuildFile; fileRef = F391171C2AB4C0BE00852298 /* missingIntentPayloadInActionLayer.json */; }; + F391171F2AB4C1C100852298 /* missingSourceSection.json in Resources */ = {isa = PBXBuildFile; fileRef = F391171E2AB4C1C100852298 /* missingSourceSection.json */; }; + F39117212AB4C20200852298 /* emptyVariantsArray.json in Resources */ = {isa = PBXBuildFile; fileRef = F39117202AB4C20200852298 /* emptyVariantsArray.json */; }; + F39117232AB4C23900852298 /* unknownSourceType.json in Resources */ = {isa = PBXBuildFile; fileRef = F39117222AB4C23900852298 /* unknownSourceType.json */; }; + F39117252AB4C27B00852298 /* missingValueInSourceLayer.json in Resources */ = {isa = PBXBuildFile; fileRef = F39117242AB4C27B00852298 /* missingValueInSourceLayer.json */; }; + F39117272AB4C2AA00852298 /* missingImageLinkInSourceLayerValue.json in Resources */ = {isa = PBXBuildFile; fileRef = F39117262AB4C2AA00852298 /* missingImageLinkInSourceLayerValue.json */; }; + F39117292AB4C2EF00852298 /* missingElementsSection.json in Resources */ = {isa = PBXBuildFile; fileRef = F39117282AB4C2EF00852298 /* missingElementsSection.json */; }; + F391172B2AB4C4AD00852298 /* invalidCloseButtonColor.json in Resources */ = {isa = PBXBuildFile; fileRef = F391172A2AB4C4AD00852298 /* invalidCloseButtonColor.json */; }; + F391172D2AB4C61000852298 /* ElementsColorFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F391172C2AB4C61000852298 /* ElementsColorFilter.swift */; }; F397EEAD2A4456C300D48CEC /* ProtocolError.swift in Sources */ = {isa = PBXBuildFile; fileRef = F397EEAC2A4456C300D48CEC /* ProtocolError.swift */; }; F397EEAF2A4456FD00D48CEC /* MindboxError.swift in Sources */ = {isa = PBXBuildFile; fileRef = F397EEAE2A4456FD00D48CEC /* MindboxError.swift */; }; F397EEB12A44571300D48CEC /* UnknownDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F397EEB02A44571300D48CEC /* UnknownDecodable.swift */; }; @@ -414,6 +435,14 @@ F3D818B32A3885F50002957C /* ABTestDeviceMixerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3D818B22A3885F50002957C /* ABTestDeviceMixerTests.swift */; }; F3D925AB2A120C0F00135C87 /* InAppImageDownloaderMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3D925AA2A120C0F00135C87 /* InAppImageDownloaderMock.swift */; }; F3D925AD2A1236F400135C87 /* URLSessionImageDownloaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3D925AC2A1236F400135C87 /* URLSessionImageDownloaderTests.swift */; }; + F3FAD86A2AB863CD00D98C03 /* missingCloseButtonColorLineWidthSize.json in Resources */ = {isa = PBXBuildFile; fileRef = F3FAD8692AB863CD00D98C03 /* missingCloseButtonColorLineWidthSize.json */; }; + F3FAD86C2AB8642C00D98C03 /* twoCloseButtonsInApp.json in Resources */ = {isa = PBXBuildFile; fileRef = F3FAD86B2AB8642C00D98C03 /* twoCloseButtonsInApp.json */; }; + F3FAD86E2AB8656700D98C03 /* closeButtonWithOpenButton.json in Resources */ = {isa = PBXBuildFile; fileRef = F3FAD86D2AB8656700D98C03 /* closeButtonWithOpenButton.json */; }; + F3FAD8702AB866B600D98C03 /* unknownSizeKind.json in Resources */ = {isa = PBXBuildFile; fileRef = F3FAD86F2AB866B600D98C03 /* unknownSizeKind.json */; }; + F3FAD8722AB8673100D98C03 /* missingMarginFieldInSection.json in Resources */ = {isa = PBXBuildFile; fileRef = F3FAD8712AB8673100D98C03 /* missingMarginFieldInSection.json */; }; + F3FAD8742AB8678900D98C03 /* negativeCloseButtonSizeValues.json in Resources */ = {isa = PBXBuildFile; fileRef = F3FAD8732AB8678900D98C03 /* negativeCloseButtonSizeValues.json */; }; + F3FAD8762AB867E700D98C03 /* closeButtonMarginAboveOne.json in Resources */ = {isa = PBXBuildFile; fileRef = F3FAD8752AB867E700D98C03 /* closeButtonMarginAboveOne.json */; }; + F3FAD8782AB8685D00D98C03 /* closeButtonMarginBelowZero.json in Resources */ = {isa = PBXBuildFile; fileRef = F3FAD8772AB8685D00D98C03 /* closeButtonMarginBelowZero.json */; }; F78E92EF282E63320003B4A3 /* DispatchSemaphore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78E92EE282E63320003B4A3 /* DispatchSemaphore.swift */; }; /* End PBXBuildFile section */ @@ -767,17 +796,13 @@ F331DC9B2A80993600222120 /* ContentElement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentElement.swift; sourceTree = ""; }; F331DC9F2A80993600222120 /* ContentElementPosition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentElementPosition.swift; sourceTree = ""; }; F331DCA12A80993600222120 /* ContentElementPositionMargin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentElementPositionMargin.swift; sourceTree = ""; }; - F331DCA32A80993600222120 /* PositionMarginKind.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PositionMarginKind.swift; sourceTree = ""; }; - F331DCA42A80993600222120 /* ContentElementPositionMarginValidator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentElementPositionMarginValidator.swift; sourceTree = ""; }; F331DCA82A80993600222120 /* ContentBackgroundLayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentBackgroundLayer.swift; sourceTree = ""; }; F331DCAD2A80993600222120 /* ContentBackgroundLayerAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentBackgroundLayerAction.swift; sourceTree = ""; }; F331DCAF2A80993600222120 /* ContentBackgroundLayerSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentBackgroundLayerSource.swift; sourceTree = ""; }; F331DCB62A80993600222120 /* ContentBackground.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentBackground.swift; sourceTree = ""; }; F331DCB72A80993600222120 /* InappFormVariantContent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InappFormVariantContent.swift; sourceTree = ""; }; F331DCB82A80993600222120 /* InappForm.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InappForm.swift; sourceTree = ""; }; - F331DCB92A80993600222120 /* InappValidator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InappValidator.swift; sourceTree = ""; }; F331DCBA2A80993600222120 /* InAppModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InAppModel.swift; sourceTree = ""; }; - F331DCE12A80B4C800222120 /* ContentElementPositionMarginValidatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentElementPositionMarginValidatorTests.swift; sourceTree = ""; }; F331DCEA2A83A56500222120 /* InAppPresentationManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InAppPresentationManager.swift; sourceTree = ""; }; F331DCEE2A83A56500222120 /* PresentationDisplayUseCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PresentationDisplayUseCase.swift; sourceTree = ""; }; F331DCF02A83A56500222120 /* ModalPresentationStrategy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ModalPresentationStrategy.swift; sourceTree = ""; }; @@ -801,13 +826,11 @@ F331DD2D2A84CA8900222120 /* UrlLayerSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UrlLayerSource.swift; sourceTree = ""; }; F331DD302A84CCA800222120 /* CloseButtonElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloseButtonElement.swift; sourceTree = ""; }; F331DD322A84D57800222120 /* VariantImageUrlExtractorService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VariantImageUrlExtractorService.swift; sourceTree = ""; }; - F331DD572A8648DB00222120 /* ContentElementSizeValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentElementSizeValidator.swift; sourceTree = ""; }; F336080C2A8A142800C7C9B7 /* SnackbarFormVariant.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnackbarFormVariant.swift; sourceTree = ""; }; F336080E2A8A14D800C7C9B7 /* SnackbarFormVariantContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnackbarFormVariantContent.swift; sourceTree = ""; }; F33608112A8A151C00C7C9B7 /* ContentPosition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentPosition.swift; sourceTree = ""; }; F33608142A8A156900C7C9B7 /* ContentPositionGravity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentPositionGravity.swift; sourceTree = ""; }; F33608172A8A161200C7C9B7 /* ContentPositionMargin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentPositionMargin.swift; sourceTree = ""; }; - F33608192A8A163D00C7C9B7 /* ContentPositionMarginValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentPositionMarginValidator.swift; sourceTree = ""; }; F336081B2A8B9EA800C7C9B7 /* SnackbarViewFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnackbarViewFactory.swift; sourceTree = ""; }; F33608252A8CC94A00C7C9B7 /* SnackbarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnackbarViewController.swift; sourceTree = ""; }; F33608272A8CD17E00C7C9B7 /* SnackbarPresentationStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnackbarPresentationStrategy.swift; sourceTree = ""; }; @@ -822,6 +845,33 @@ F3482F222A65DC37002A41EC /* InAppMessagesDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InAppMessagesDelegate.swift; sourceTree = ""; }; F3482F292A65DCFC002A41EC /* String+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Extensions.swift"; sourceTree = ""; }; F37613E02A6A8CFF009F2EE4 /* UIColor+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Extensions.swift"; sourceTree = ""; }; + F39116ED2AA53EE400852298 /* VariantImageUrlExtractorServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VariantImageUrlExtractorServiceTests.swift; sourceTree = ""; }; + F39116F42AA9AF7A00852298 /* InappFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InappFilter.swift; sourceTree = ""; }; + F39116F72AA9B04E00852298 /* VariantsFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VariantsFilter.swift; sourceTree = ""; }; + F39116F92AA9B32E00852298 /* LayersFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayersFilter.swift; sourceTree = ""; }; + F39116FB2AA9B4A200852298 /* LayerActionFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayerActionFilter.swift; sourceTree = ""; }; + F39116FD2AA9B54B00852298 /* LayersSourceFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayersSourceFilter.swift; sourceTree = ""; }; + F39117002AA9B68B00852298 /* ElementsFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementsFilter.swift; sourceTree = ""; }; + F39117022AA9B79100852298 /* ElementsSizeFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementsSizeFilter.swift; sourceTree = ""; }; + F39117042AA9B92500852298 /* ElementsPositionFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementsPositionFilter.swift; sourceTree = ""; }; + F39117062AA9C69A00852298 /* ContentPositionFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentPositionFilter.swift; sourceTree = ""; }; + F391170A2AB2E74F00852298 /* InappFilterServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InappFilterServiceTests.swift; sourceTree = ""; }; + F391170E2AB4B31800852298 /* unknownVariantType.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = unknownVariantType.json; sourceTree = ""; }; + F39117102AB4BD4500852298 /* missingBackgroundSection.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = missingBackgroundSection.json; sourceTree = ""; }; + F39117122AB4BD8500852298 /* emptyLayersSection.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = emptyLayersSection.json; sourceTree = ""; }; + F39117142AB4BEB900852298 /* unknownLayerType.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = unknownLayerType.json; sourceTree = ""; }; + F39117162AB4BF2700852298 /* knownImageUnknownPictureLayerType.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = knownImageUnknownPictureLayerType.json; sourceTree = ""; }; + F39117182AB4C02500852298 /* unknownActionLayerType.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = unknownActionLayerType.json; sourceTree = ""; }; + F391171A2AB4C07900852298 /* redirectUrlValueNumberInsteadOfString.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = redirectUrlValueNumberInsteadOfString.json; sourceTree = ""; }; + F391171C2AB4C0BE00852298 /* missingIntentPayloadInActionLayer.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = missingIntentPayloadInActionLayer.json; sourceTree = ""; }; + F391171E2AB4C1C100852298 /* missingSourceSection.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = missingSourceSection.json; sourceTree = ""; }; + F39117202AB4C20200852298 /* emptyVariantsArray.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = emptyVariantsArray.json; sourceTree = ""; }; + F39117222AB4C23900852298 /* unknownSourceType.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = unknownSourceType.json; sourceTree = ""; }; + F39117242AB4C27B00852298 /* missingValueInSourceLayer.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = missingValueInSourceLayer.json; sourceTree = ""; }; + F39117262AB4C2AA00852298 /* missingImageLinkInSourceLayerValue.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = missingImageLinkInSourceLayerValue.json; sourceTree = ""; }; + F39117282AB4C2EF00852298 /* missingElementsSection.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = missingElementsSection.json; sourceTree = ""; }; + F391172A2AB4C4AD00852298 /* invalidCloseButtonColor.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = invalidCloseButtonColor.json; sourceTree = ""; }; + F391172C2AB4C61000852298 /* ElementsColorFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementsColorFilter.swift; sourceTree = ""; }; F397EEAC2A4456C300D48CEC /* ProtocolError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProtocolError.swift; sourceTree = ""; }; F397EEAE2A4456FD00D48CEC /* MindboxError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MindboxError.swift; sourceTree = ""; }; F397EEB02A44571300D48CEC /* UnknownDecodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnknownDecodable.swift; sourceTree = ""; }; @@ -869,6 +919,14 @@ F3D818B22A3885F50002957C /* ABTestDeviceMixerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ABTestDeviceMixerTests.swift; sourceTree = ""; }; F3D925AA2A120C0F00135C87 /* InAppImageDownloaderMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InAppImageDownloaderMock.swift; sourceTree = ""; }; F3D925AC2A1236F400135C87 /* URLSessionImageDownloaderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLSessionImageDownloaderTests.swift; sourceTree = ""; }; + F3FAD8692AB863CD00D98C03 /* missingCloseButtonColorLineWidthSize.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = missingCloseButtonColorLineWidthSize.json; sourceTree = ""; }; + F3FAD86B2AB8642C00D98C03 /* twoCloseButtonsInApp.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = twoCloseButtonsInApp.json; sourceTree = ""; }; + F3FAD86D2AB8656700D98C03 /* closeButtonWithOpenButton.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = closeButtonWithOpenButton.json; sourceTree = ""; }; + F3FAD86F2AB866B600D98C03 /* unknownSizeKind.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = unknownSizeKind.json; sourceTree = ""; }; + F3FAD8712AB8673100D98C03 /* missingMarginFieldInSection.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = missingMarginFieldInSection.json; sourceTree = ""; }; + F3FAD8732AB8678900D98C03 /* negativeCloseButtonSizeValues.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = negativeCloseButtonSizeValues.json; sourceTree = ""; }; + F3FAD8752AB867E700D98C03 /* closeButtonMarginAboveOne.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = closeButtonMarginAboveOne.json; sourceTree = ""; }; + F3FAD8772AB8685D00D98C03 /* closeButtonMarginBelowZero.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = closeButtonMarginBelowZero.json; sourceTree = ""; }; F78E92EE282E63320003B4A3 /* DispatchSemaphore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DispatchSemaphore.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -1948,7 +2006,6 @@ isa = PBXGroup; children = ( F331DCBA2A80993600222120 /* InAppModel.swift */, - F331DCB92A80993600222120 /* InappValidator.swift */, F331DC8D2A80993600222120 /* InappForm */, ); path = InappModel; @@ -2000,7 +2057,6 @@ isa = PBXGroup; children = ( F331DC982A80993600222120 /* ContentElementSize.swift */, - F331DD572A8648DB00222120 /* ContentElementSizeValidator.swift */, F331DC992A80993600222120 /* Kind */, ); path = ContentElementSize; @@ -2027,20 +2083,10 @@ isa = PBXGroup; children = ( F331DCA12A80993600222120 /* ContentElementPositionMargin.swift */, - F331DCA22A80993600222120 /* PositionMarginKind */, - F331DCA42A80993600222120 /* ContentElementPositionMarginValidator.swift */, ); path = ContentElementPositionMargin; sourceTree = ""; }; - F331DCA22A80993600222120 /* PositionMarginKind */ = { - isa = PBXGroup; - children = ( - F331DCA32A80993600222120 /* PositionMarginKind.swift */, - ); - path = PositionMarginKind; - sourceTree = ""; - }; F331DCA62A80993600222120 /* ContentBackground */ = { isa = PBXGroup; children = ( @@ -2082,7 +2128,6 @@ F331DCDA2A80AC3300222120 /* ModelValidatorTests */ = { isa = PBXGroup; children = ( - F331DCE12A80B4C800222120 /* ContentElementPositionMarginValidatorTests.swift */, ); path = ModelValidatorTests; sourceTree = ""; @@ -2263,7 +2308,6 @@ isa = PBXGroup; children = ( F33608172A8A161200C7C9B7 /* ContentPositionMargin.swift */, - F33608192A8A163D00C7C9B7 /* ContentPositionMarginValidator.swift */, ); path = ContentPositionMargin; sourceTree = ""; @@ -2324,6 +2368,78 @@ path = Extensions; sourceTree = ""; }; + F39116F32AA9AF3C00852298 /* InappFilterService */ = { + isa = PBXGroup; + children = ( + F39116F42AA9AF7A00852298 /* InappFilter.swift */, + F39116F72AA9B04E00852298 /* VariantsFilter.swift */, + F39116FF2AA9B67E00852298 /* LayersFilter */, + F39117082AAA48CF00852298 /* ElementsFiter */, + F39117062AA9C69A00852298 /* ContentPositionFilter.swift */, + ); + path = InappFilterService; + sourceTree = ""; + }; + F39116FF2AA9B67E00852298 /* LayersFilter */ = { + isa = PBXGroup; + children = ( + F39116F92AA9B32E00852298 /* LayersFilter.swift */, + F39116FB2AA9B4A200852298 /* LayerActionFilter.swift */, + F39116FD2AA9B54B00852298 /* LayersSourceFilter.swift */, + ); + path = LayersFilter; + sourceTree = ""; + }; + F39117082AAA48CF00852298 /* ElementsFiter */ = { + isa = PBXGroup; + children = ( + F39117002AA9B68B00852298 /* ElementsFilter.swift */, + F39117022AA9B79100852298 /* ElementsSizeFilter.swift */, + F39117042AA9B92500852298 /* ElementsPositionFilter.swift */, + F391172C2AB4C61000852298 /* ElementsColorFilter.swift */, + ); + path = ElementsFiter; + sourceTree = ""; + }; + F391170C2AB4B2FC00852298 /* InappFilterServiceTests */ = { + isa = PBXGroup; + children = ( + F391170D2AB4B30600852298 /* JSON */, + F391170A2AB2E74F00852298 /* InappFilterServiceTests.swift */, + ); + path = InappFilterServiceTests; + sourceTree = ""; + }; + F391170D2AB4B30600852298 /* JSON */ = { + isa = PBXGroup; + children = ( + F3FAD8772AB8685D00D98C03 /* closeButtonMarginBelowZero.json */, + F3FAD8752AB867E700D98C03 /* closeButtonMarginAboveOne.json */, + F3FAD8732AB8678900D98C03 /* negativeCloseButtonSizeValues.json */, + F3FAD8712AB8673100D98C03 /* missingMarginFieldInSection.json */, + F3FAD86F2AB866B600D98C03 /* unknownSizeKind.json */, + F3FAD86D2AB8656700D98C03 /* closeButtonWithOpenButton.json */, + F3FAD86B2AB8642C00D98C03 /* twoCloseButtonsInApp.json */, + F3FAD8692AB863CD00D98C03 /* missingCloseButtonColorLineWidthSize.json */, + F391172A2AB4C4AD00852298 /* invalidCloseButtonColor.json */, + F39117282AB4C2EF00852298 /* missingElementsSection.json */, + F39117262AB4C2AA00852298 /* missingImageLinkInSourceLayerValue.json */, + F39117242AB4C27B00852298 /* missingValueInSourceLayer.json */, + F39117222AB4C23900852298 /* unknownSourceType.json */, + F39117202AB4C20200852298 /* emptyVariantsArray.json */, + F391171E2AB4C1C100852298 /* missingSourceSection.json */, + F391171C2AB4C0BE00852298 /* missingIntentPayloadInActionLayer.json */, + F391171A2AB4C07900852298 /* redirectUrlValueNumberInsteadOfString.json */, + F39117182AB4C02500852298 /* unknownActionLayerType.json */, + F39117162AB4BF2700852298 /* knownImageUnknownPictureLayerType.json */, + F39117142AB4BEB900852298 /* unknownLayerType.json */, + F39117122AB4BD8500852298 /* emptyLayersSection.json */, + F39117102AB4BD4500852298 /* missingBackgroundSection.json */, + F391170E2AB4B31800852298 /* unknownVariantType.json */, + ); + path = "JSON "; + sourceTree = ""; + }; F397EEAB2A4456A900D48CEC /* MindboxError */ = { isa = PBXGroup; children = ( @@ -2393,6 +2509,7 @@ F3A8B9562A389D9300E9C055 /* Services */ = { isa = PBXGroup; children = ( + F39116F32AA9AF3C00852298 /* InappFilterService */, F3A8B9572A389D9D00E9C055 /* GeoService.swift */, F39B67A12A3C6AF4005C0CCA /* SegmentationService.swift */, F39B67A82A3C72E5005C0CCA /* ImageDownloadService.swift */, @@ -2407,6 +2524,8 @@ F39B67AA2A3C7304005C0CCA /* ImageDownloadService */, F3A8B95B2A389EAD00E9C055 /* GeoServiceTests.swift */, F39B67A62A3C6C6A005C0CCA /* SegmentationServiceTests.swift */, + F39116ED2AA53EE400852298 /* VariantImageUrlExtractorServiceTests.swift */, + F391170C2AB4B2FC00852298 /* InappFilterServiceTests */, ); path = InAppConfigurationMapperTests; sourceTree = ""; @@ -2650,21 +2769,34 @@ files = ( A1B940B7298104ED00B0F994 /* UnknownTargetingsModel.json in Resources */, F39B67C82A3FBEA7005C0CCA /* ConfigWithABTypeNotInapps.json in Resources */, + F3FAD8782AB8685D00D98C03 /* closeButtonMarginBelowZero.json in Resources */, + F39117132AB4BD8500852298 /* emptyLayersSection.json in Resources */, F39B67BC2A3FB9A8005C0CCA /* ConfigWithABNoSalt.json in Resources */, 31ED2DF325C4456600301FAD /* TestConfig_Invalid_1.plist in Resources */, + F39117192AB4C02500852298 /* unknownActionLayerType.json in Resources */, + F39117152AB4BEB900852298 /* unknownLayerType.json in Resources */, A153E04129BB0A8B003C34D4 /* InAppConfigurationWithOperations.json in Resources */, F31801FF2A386BE60021774C /* InappConfigResponseMonitoringInvalid.json in Resources */, 31ED2DF225C4456600301FAD /* TestConfig_Invalid_2.plist in Resources */, + F39117172AB4BF2700852298 /* knownImageUnknownPictureLayerType.json in Resources */, 31ED2DF425C4456600301FAD /* TestConfig_Invalid_3.plist in Resources */, + F3FAD8722AB8673100D98C03 /* missingMarginFieldInSection.json in Resources */, 84CC79AB25CAEBBB00C062BD /* TestEventConfig.plist in Resources */, F31801FB2A386A5B0021774C /* InappConfigResponseSettingsInvalid.json in Resources */, F39B67BE2A3FB9EF005C0CCA /* ConfigWithABUnexpectedValue.json in Resources */, A17958902978BE7000609E91 /* GeoTargetingModelValid.json in Resources */, + F3FAD86C2AB8642C00D98C03 /* twoCloseButtonsInApp.json in Resources */, + F3FAD8742AB8678900D98C03 /* negativeCloseButtonSizeValues.json in Resources */, F3A8B9452A38870100E9C055 /* MixerUUIDS.json in Resources */, + F391171B2AB4C07900852298 /* redirectUrlValueNumberInsteadOfString.json in Resources */, A179588D2978BE7000609E91 /* SegmentTargetingModelValid.json in Resources */, 9BE941F52916822900258077 /* InAppConfigurationInvalid.json in Resources */, + F3FAD8702AB866B600D98C03 /* unknownSizeKind.json in Resources */, + F3FAD86E2AB8656700D98C03 /* closeButtonWithOpenButton.json in Resources */, F39B67C22A3FBB19005C0CCA /* ConfigWithABNoUpper.json in Resources */, + F39117292AB4C2EF00852298 /* missingElementsSection.json in Resources */, F39B67C02A3FBA77005C0CCA /* ConfigWithABCrossRange.json in Resources */, + F3FAD8762AB867E700D98C03 /* closeButtonMarginAboveOne.json in Resources */, F31801FE2A386BE60021774C /* InappConfigResponseAbtestsInvalid.json in Resources */, A1A916E329C914C000D59D9E /* InAppConfigurationWithCategoryIDIn.json in Resources */, A17958922978C88B00609E91 /* AllTargetingsModelValid.json in Resources */, @@ -2672,16 +2804,26 @@ F39B67B32A3C8B1D005C0CCA /* ConfigWithAB_2.json in Resources */, A179588C2978BE7000609E91 /* OrTargetingModelValid.json in Resources */, A179588F2978BE7000609E91 /* TrueTargetingModelValid.json in Resources */, + F391172B2AB4C4AD00852298 /* invalidCloseButtonColor.json in Resources */, 31ED2DFA25C4459500301FAD /* TestConfig_Invalid_4.plist in Resources */, F39B67C62A3FBC47005C0CCA /* ConfigWithABNormal.json in Resources */, F31801F82A38649D0021774C /* InappConfigResponseValid.json in Resources */, F39B67B22A3C8B1D005C0CCA /* ConfigWithAB_1.json in Resources */, 84FCD3BD25CA10F600D1E574 /* SuccessResponse.json in Resources */, + F39117212AB4C20200852298 /* emptyVariantsArray.json in Resources */, + F39117252AB4C27B00852298 /* missingValueInSourceLayer.json in Resources */, F39B67C42A3FBB64005C0CCA /* ConfigWithABLowerBiggerThanUpper.json in Resources */, + F391171D2AB4C0BE00852298 /* missingIntentPayloadInActionLayer.json in Resources */, + F39117112AB4BD4500852298 /* missingBackgroundSection.json in Resources */, 31EB907425C402F900368FFB /* TestConfig2.plist in Resources */, 31EB907325C402F900368FFB /* TestConfig3.plist in Resources */, + F391170F2AB4B31800852298 /* unknownVariantType.json in Resources */, + F39117232AB4C23900852298 /* unknownSourceType.json in Resources */, + F391171F2AB4C1C100852298 /* missingSourceSection.json in Resources */, + F39117272AB4C2AA00852298 /* missingImageLinkInSourceLayerValue.json in Resources */, F39B67BA2A3FB943005C0CCA /* ConfigWithABBrokenRange.json in Resources */, 31A20D4925B6CBE000AAA0A3 /* TestConfig1.plist in Resources */, + F3FAD86A2AB863CD00D98C03 /* missingCloseButtonColorLineWidthSize.json in Resources */, 9BC24E7A28F6C08700C2619C /* InAppConfiguration.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2748,6 +2890,7 @@ 33072F442664CC6C001F1AB2 /* IssuedPointOfContactResponse.swift in Sources */, A17958762978AEC600609E91 /* OrTargetingChecker.swift in Sources */, 334F3AE1264C199900A6AC00 /* PromoCodeRequest.swift in Sources */, + F39116F52AA9AF7A00852298 /* InappFilter.swift in Sources */, F331DD032A83A56500222120 /* ModalPresentationStrategy.swift in Sources */, A17958792978AEC600609E91 /* GeoTargetingChecker.swift in Sources */, 33BEE80D2681EB7700993720 /* NotificationDecoder.swift in Sources */, @@ -2818,15 +2961,16 @@ F39B67A22A3C6AF4005C0CCA /* SegmentationService.swift in Sources */, 334F3AEC264C199900A6AC00 /* RequestedPromotionRequest.swift in Sources */, 84DEE8B125CC042A00C98CC7 /* MBDatabaseError.swift in Sources */, + F39117072AA9C69A00852298 /* ContentPositionFilter.swift in Sources */, A179587C2978AED800609E91 /* GeoTargeting.swift in Sources */, 3333C1E12681EA4D00B60D84 /* NotificationsPayloads.swift in Sources */, 334F3AE7264C199900A6AC00 /* CatalogProductListRequest.swift in Sources */, F331DCC02A80993600222120 /* ContentElementSizeType.swift in Sources */, - F331DCC52A80993600222120 /* PositionMarginKind.swift in Sources */, F331DD0B2A83A56500222120 /* CrossView.swift in Sources */, B3A625562689FDD400B6A3B7 /* BalanceResponse.swift in Sources */, 6FDD1459266F7CB700A50C35 /* ContentResponse.swift in Sources */, F37613E12A6A8CFF009F2EE4 /* UIColor+Extensions.swift in Sources */, + F39116F82AA9B04E00852298 /* VariantsFilter.swift in Sources */, F3A8B9582A389D9D00E9C055 /* GeoService.swift in Sources */, 334F3AE2264C199900A6AC00 /* CouponRequest.swift in Sources */, F3A8B9942A3A409C00E9C055 /* Validator.swift in Sources */, @@ -2845,7 +2989,6 @@ 334F3AEB264C199900A6AC00 /* DiscountCardRequest.swift in Sources */, 31A20D4E25B6EFB600AAA0A3 /* MindboxDelegate.swift in Sources */, A179587A2978AEC600609E91 /* AndTargetingChecker.swift in Sources */, - F331DD582A8648DB00222120 /* ContentElementSizeValidator.swift in Sources */, F3482F1B2A65DC01002A41EC /* DefaultInappMessageDelegate.swift in Sources */, F331DD012A83A56500222120 /* InAppPresentationManager.swift in Sources */, 3337E6A3265FAB39006949EB /* BaseResponse.swift in Sources */, @@ -2886,6 +3029,7 @@ 337A47362654F995000DC613 /* OperationBodyRequest.swift in Sources */, 9BC24E6F28F694EA00C2619C /* SDKVersionProvider.swift in Sources */, 6FDD144D266F7C6600A50C35 /* AmountTypeResponse.swift in Sources */, + F39117012AA9B68B00852298 /* ElementsFilter.swift in Sources */, 6FDD1461266F7CE300A50C35 /* DiscountAmountTypeResponse.swift in Sources */, 6FDD144F266F7C7000A50C35 /* UsedResponse.swift in Sources */, 330D8CCD26579581005106D5 /* Channel.swift in Sources */, @@ -2901,6 +3045,7 @@ A1D017F22976CC9400CD9F99 /* SegmentTargeting.swift in Sources */, F331DD072A83A56500222120 /* CloseButtonElementFactory.swift in Sources */, 9BC24E7428F6953D00C2619C /* InAppConfigurationAPI.swift in Sources */, + F39117032AA9B79100852298 /* ElementsSizeFilter.swift in Sources */, F397EEB32A44572400D48CEC /* ValidationError.swift in Sources */, A192787229D442D900CDB53D /* ProductSegmentChecker.swift in Sources */, A153E03D29BAFEC1003C34D4 /* CustomOperationChecker.swift in Sources */, @@ -2921,9 +3066,11 @@ 84A0CD54260AF8C8004CD91B /* TrackClick.swift in Sources */, A1D017F02976CC8600CD9F99 /* OrTargeting.swift in Sources */, 334F3AEA264C199900A6AC00 /* CustomerRequest.swift in Sources */, + F391172D2AB4C61000852298 /* ElementsColorFilter.swift in Sources */, A15D701629AF810E007131E7 /* SDKLogsRequest.swift in Sources */, 33072F362664C4D7001F1AB2 /* RecommendationRequest.swift in Sources */, 84DC49CC25D1832300D5D758 /* EventWrapper.swift in Sources */, + F39116FA2AA9B32E00852298 /* LayersFilter.swift in Sources */, 317054C425AEF88E00AE624C /* DependencyProvider.swift in Sources */, 84DC4A0225D27D0500D5D758 /* UNAuthorizationStatusProviding.swift in Sources */, 6FDD1465266F7CFE00A50C35 /* ItemProductResponse.swift in Sources */, @@ -2939,6 +3086,7 @@ 334F3AF0264C199900A6AC00 /* DiscountRequest.swift in Sources */, F331DD1F2A84B62200222120 /* RedirectUrlLayerAction.swift in Sources */, 847F57FE25C88BB700147A9A /* HTTPMethod.swift in Sources */, + F39117052AA9B92500852298 /* ElementsPositionFilter.swift in Sources */, 334F3AE9264C199900A6AC00 /* OrderRequest.swift in Sources */, 9B24FAAC28C74B8300F10B5D /* InAppConfigurationRepository.swift in Sources */, F33608122A8A151C00C7C9B7 /* ContentPosition.swift in Sources */, @@ -2953,6 +3101,7 @@ 334F3AEF264C199900A6AC00 /* DiscountPromoCodeRequest.swift in Sources */, 84F5655E2628434D00269FD6 /* TrackVisitManager.swift in Sources */, F397EEAF2A4456FD00D48CEC /* MindboxError.swift in Sources */, + F39116FC2AA9B4A200852298 /* LayerActionFilter.swift in Sources */, 3337E6A52660D878006949EB /* OperationResponse.swift in Sources */, B3F4F98E268EEB4B0092EC3C /* LimitBenefitsResponse.swift in Sources */, 9B4F9DF928D088A9002C9CF0 /* InAppConfig.swift in Sources */, @@ -2990,7 +3139,6 @@ 33EBF0B0264E6283002A35D5 /* SessionManager.swift in Sources */, F331DD192A840D2100222120 /* ModalFormVariant.swift in Sources */, F331DD2E2A84CA8900222120 /* UrlLayerSource.swift in Sources */, - F336081A2A8A163D00C7C9B7 /* ContentPositionMarginValidator.swift in Sources */, 337C7952265646D10092B580 /* OperationBodyRequestType.swift in Sources */, 9B9C95312921116F00BB29DA /* UUIDDebugService.swift in Sources */, 6FDD1443266F7C1600A50C35 /* BalanceTypeReponse.swift in Sources */, @@ -3000,17 +3148,16 @@ 3191C2A625ADFD8000E7D6B9 /* Mindbox.swift in Sources */, A184654529C310F100E64780 /* InAppOperationJSONModel.swift in Sources */, A154E330299E0F1600F8F074 /* InAppGeoResponse.swift in Sources */, - F331DCC62A80993600222120 /* ContentElementPositionMarginValidator.swift in Sources */, F39B67A92A3C72E5005C0CCA /* ImageDownloadService.swift in Sources */, 84CC799725CACF5500C062BD /* MBEventRepository.swift in Sources */, F3482F172A65DBB7002A41EC /* MindboxURLHandlerDelegate.swift in Sources */, F33608182A8A161200C7C9B7 /* ContentPositionMargin.swift in Sources */, 847F581F25C8A3F500147A9A /* HTTPTypealiases.swift in Sources */, 33BEE8172681EC5F00993720 /* EventRoute.swift in Sources */, - F331DCD42A80993600222120 /* InappValidator.swift in Sources */, 317054CB25AF189800AE624C /* PersistenceStorage.swift in Sources */, F331DD092A83A56500222120 /* LayerFactory.swift in Sources */, F336080D2A8A142800C7C9B7 /* SnackbarFormVariant.swift in Sources */, + F39116FE2AA9B54B00852298 /* LayersSourceFilter.swift in Sources */, 840C38AC25D11BB200D50183 /* DeliveryOperation.swift in Sources */, 334F3AEE264C199900A6AC00 /* SegmentationRequest.swift in Sources */, B3A625502689F8B600B6A3B7 /* BenefitResponse.swift in Sources */, @@ -3034,7 +3181,6 @@ A17958992978E04600609E91 /* InAppStub.swift in Sources */, F39B67A72A3C6C6A005C0CCA /* SegmentationServiceTests.swift in Sources */, F3D925AB2A120C0F00135C87 /* InAppImageDownloaderMock.swift in Sources */, - F331DCE22A80B4C800222120 /* ContentElementPositionMarginValidatorTests.swift in Sources */, A154E32E299E0D8900F8F074 /* SDKLogManagerTests.swift in Sources */, 9B52570728D1AF880029B1BC /* InAppPresentationManagerMock.swift in Sources */, 84B09FB42611C74400B0A06E /* MockDatabaseRepository.swift in Sources */, @@ -3049,6 +3195,7 @@ 848A895E2620C54900EDFB6D /* VersioningTestCase.swift in Sources */, A1A916E529C9191900D59D9E /* InAppConfigStub.swift in Sources */, 313B233F25ADEA0F00A1CB72 /* MindboxTests.swift in Sources */, + F39116EE2AA53EE400852298 /* VariantImageUrlExtractorServiceTests.swift in Sources */, A154E334299E110E00F8F074 /* EventRepositoryMock.swift in Sources */, 31ED2DEC25C444C400301FAD /* MBConfigurationTestCase.swift in Sources */, F3D925AD2A1236F400135C87 /* URLSessionImageDownloaderTests.swift in Sources */, @@ -3067,6 +3214,7 @@ 848A89592620C3AE00EDFB6D /* APNSTokenGenerator.swift in Sources */, F3D818B32A3885F50002957C /* ABTestDeviceMixerTests.swift in Sources */, 9BC24E7728F6BF8C00C2619C /* InAppConfigResponseTests.swift in Sources */, + F391170B2AB2E74F00852298 /* InappFilterServiceTests.swift in Sources */, F39B67AC2A3C7315005C0CCA /* MockImageDownloadService.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Mindbox/DI/DependencyContainer.swift b/Mindbox/DI/DependencyContainer.swift index eb3d00a4..07cd1a99 100644 --- a/Mindbox/DI/DependencyContainer.swift +++ b/Mindbox/DI/DependencyContainer.swift @@ -28,6 +28,7 @@ protocol DependencyContainer { var imageDownloadService: ImageDownloadServiceProtocol { get } var abTestDeviceMixer: ABTestDeviceMixer { get } var urlExtractorService: VariantImageUrlExtractorService { get } + var inappFilterService: InappFilterProtocol { get } } protocol InstanceFactory { diff --git a/Mindbox/DI/DependencyProvider.swift b/Mindbox/DI/DependencyProvider.swift index 137c5f00..24a62b7e 100644 --- a/Mindbox/DI/DependencyProvider.swift +++ b/Mindbox/DI/DependencyProvider.swift @@ -30,6 +30,7 @@ final class DependencyProvider: DependencyContainer { var imageDownloadService: ImageDownloadServiceProtocol var abTestDeviceMixer: ABTestDeviceMixer var urlExtractorService: VariantImageUrlExtractorService + var inappFilterService: InappFilterProtocol init() throws { utilitiesFetcher = MBUtilitiesFetcher() @@ -69,11 +70,24 @@ final class DependencyProvider: DependencyContainer { let presentationManager = InAppPresentationManager(actionHandler: actionHandler, displayUseCase: displayUseCase) urlExtractorService = VariantImageUrlExtractorService() + let actionFilter = LayerActionFilterService() + 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, colorFilter: colorFilter) + let contentPositionFilterService = ContentPositionFilterService() + let variantsFilterService = VariantFilterService(layersFilter: layersFilterService, + elementsFilter: elementsFilterService, + contentPositionFilter: contentPositionFilterService) + inappFilterService = InappsFilterService(variantsFilter: variantsFilterService) inAppMessagesManager = InAppCoreManager( configManager: InAppConfigurationManager( inAppConfigAPI: InAppConfigurationAPI(persistenceStorage: persistenceStorage), inAppConfigRepository: InAppConfigurationRepository(), - inAppConfigurationMapper: InAppConfigutationMapper(geoService: geoService, + inAppConfigurationMapper: InAppConfigutationMapper(inappFilterService: inappFilterService, + geoService: geoService, segmentationService: segmentationSevice, customerSegmentsAPI: .live, targetingChecker: inAppTargetingChecker, diff --git a/Mindbox/InAppMessages/Configuration/InAppConfigurationManager.swift b/Mindbox/InAppMessages/Configuration/InAppConfigurationManager.swift index 002ca977..4205d359 100644 --- a/Mindbox/InAppMessages/Configuration/InAppConfigurationManager.swift +++ b/Mindbox/InAppMessages/Configuration/InAppConfigurationManager.swift @@ -139,7 +139,7 @@ class InAppConfigurationManager: InAppConfigurationManagerProtocol { rawConfigurationResponse = configResponse inAppConfigurationMapper.mapConfigResponse(event, configResponse, { inapp in self.inapp = inapp - Logger.common(message: "In-app сonfiguration applied: \n\(String(describing: inapp))", level: .debug, category: .inAppMessages) + Logger.common(message: "In-app applied: \(String(describing: inapp?.inAppId)))", level: .debug, category: .inAppMessages) self.delegate?.didPreparedConfiguration() }) } diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/InAppConfigutationMapper.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/InAppConfigutationMapper.swift index fc3e668c..2d3167fb 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/InAppConfigutationMapper.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/InAppConfigutationMapper.swift @@ -16,6 +16,7 @@ protocol InAppConfigurationMapperProtocol { final class InAppConfigutationMapper: InAppConfigurationMapperProtocol { + private let inappFilterService: InappFilterProtocol private let geoService: GeoServiceProtocol private let segmentationService: SegmentationServiceProtocol private let customerSegmentsAPI: CustomerSegmentsAPI @@ -25,12 +26,13 @@ final class InAppConfigutationMapper: InAppConfigurationMapperProtocol { var filteredInAppsByEvent: [InAppMessageTriggerEvent: [InAppTransitionData]] = [:] private let sdkVersionValidator: SDKVersionValidator private let imageDownloadService: ImageDownloadServiceProtocol - private let urlExtractorService: VariantImageUrlExtractorService + private let urlExtractorService: VariantImageUrlExtractorServiceProtocol private let abTestDeviceMixer: ABTestDeviceMixer private let dispatchGroup = DispatchGroup() - init(geoService: GeoServiceProtocol, + init(inappFilterService: InappFilterProtocol, + geoService: GeoServiceProtocol, segmentationService: SegmentationServiceProtocol, customerSegmentsAPI: CustomerSegmentsAPI, targetingChecker: InAppTargetingCheckerProtocol, @@ -38,8 +40,9 @@ final class InAppConfigutationMapper: InAppConfigurationMapperProtocol { persistenceStorage: PersistenceStorage, sdkVersionValidator: SDKVersionValidator, imageDownloadService: ImageDownloadServiceProtocol, - urlExtractorService: VariantImageUrlExtractorService, + urlExtractorService: VariantImageUrlExtractorServiceProtocol, abTestDeviceMixer: ABTestDeviceMixer) { + self.inappFilterService = inappFilterService self.geoService = geoService self.segmentationService = segmentationService self.customerSegmentsAPI = customerSegmentsAPI @@ -57,7 +60,8 @@ final class InAppConfigutationMapper: InAppConfigurationMapperProtocol { _ response: ConfigResponse, _ completion: @escaping (InAppFormData?) -> Void) { let shownInAppsIds = Set(persistenceStorage.shownInAppsIds ?? []) - let responseInapps = filterInappsByABTests(response.abtests, responseInapps: response.inapps?.elements) + let inapps = inappFilterService.filter(inapps: response.inapps?.elements) + let responseInapps = filterInappsByABTests(response.abtests, responseInapps: inapps) let filteredInapps = filterInappsBySDKVersion(responseInapps, shownInAppsIds: shownInAppsIds) Logger.common(message: "Shown in-apps ids: [\(shownInAppsIds)]", level: .info, category: .inAppMessages) if filteredInapps.isEmpty { @@ -242,7 +246,7 @@ final class InAppConfigutationMapper: InAppConfigurationMapperProtocol { } var inAppsForEvent = filteredInAppsByEvent[triggerEvent] ?? [InAppTransitionData]() - if let inAppFormVariants = inapp.form.variants.elements.first { + if let inAppFormVariants = inapp.form.variants.first { let formData = InAppTransitionData(inAppId: inapp.id, content: inAppFormVariants) inAppsForEvent.append(formData) @@ -255,39 +259,53 @@ final class InAppConfigutationMapper: InAppConfigurationMapperProtocol { private func buildInAppByEvent(inapps: [InAppTransitionData], completion: @escaping (InAppFormData?) -> Void) { - var shouldDownloadImage = true var formData: InAppFormData? let group = DispatchGroup() + let imageDictQueue = DispatchQueue(label: "com.mindbox.imagedict.queue", attributes: .concurrent) DispatchQueue.global().async { for inapp in inapps { - if !shouldDownloadImage { + guard formData == nil else { break } + var imageDict: [String: UIImage] = [:] + var gotError = false + if let shownInapps = self.persistenceStorage.shownInAppsIds, shownInapps.contains(inapp.inAppId) { continue } - guard let imageValue = self.urlExtractorService.extractImageURL(from: inapp.content) else { continue } + let imageValues = self.urlExtractorService.extractImageURL(from: inapp.content) - group.enter() - Logger.common(message: "Starting inapp processing. [ID]: \(inapp.inAppId)", level: .debug, category: .inAppMessages) - - self.imageDownloadService.downloadImage(withUrl: imageValue) { result in - defer { group.leave() } - switch result { - case .success(let image): - formData = InAppFormData(inAppId: inapp.inAppId, - image: image, - content: inapp.content) - shouldDownloadImage = false - case .failure: - break + Logger.common(message: "Starting in-app processing. [ID]: \(inapp.inAppId)", level: .debug, category: .inAppMessages) + for imageValue in imageValues { + group.enter() + Logger.common(message: "Initiating the process of image loading from the URL: \(imageValue)", level: .debug, category: .inAppMessages) + self.imageDownloadService.downloadImage(withUrl: imageValue) { result in + defer { + group.leave() + } + + switch result { + case .success(let image): + imageDictQueue.async(flags: .barrier) { + imageDict[imageValue] = image + } + case .failure: + gotError = true + } } } group.wait() + + imageDictQueue.sync { + if !imageDict.isEmpty && !gotError { + let firstImageValue = imageValues.first ?? "" + formData = InAppFormData(inAppId: inapp.inAppId, imagesDict: imageDict, firstImageValue: firstImageValue, content: inapp.content) + } + } } group.notify(queue: .main) { diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/ImageDownloadService.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/ImageDownloadService.swift index 7731baad..28ffce50 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/ImageDownloadService.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/ImageDownloadService.swift @@ -24,7 +24,7 @@ class ImageDownloadService: ImageDownloadServiceProtocol { func downloadImage(withUrl url: String, completion: @escaping (Result) -> Void) { self.imageDownloader.downloadImage(withUrl: url) { localURL, response, error in if let error = error as? NSError { - Logger.common(message: "Failed to download image for url: \(url). \nError: \(error.localizedDescription)", level: .debug, category: .inAppMessages) + Logger.common(message: "Failed to download image. [URL]: \(url). \nError: \(error.localizedDescription)", level: .debug, category: .inAppMessages) if error.code == NSURLErrorTimedOut { completion(.failure(error)) } else { diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ContentPositionFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ContentPositionFilter.swift new file mode 100644 index 00000000..134729b3 --- /dev/null +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ContentPositionFilter.swift @@ -0,0 +1,69 @@ +// +// ContentPositionFilter.swift +// Mindbox +// +// Created by vailence on 07.09.2023. +// Copyright © 2023 Mindbox. All rights reserved. +// + +import Foundation +import MindboxLogger + +protocol ContentPositionFilterProtocol { + func filter(_ contentPosition: ContentPositionDTO?) throws -> ContentPosition +} + +final class ContentPositionFilterService: ContentPositionFilterProtocol { + + enum Constants { + static let defaultGravity = ContentPositionGravity(vertical: .bottom, horizontal: .center) + static let defaultMargin = ContentPositionMargin(kind: .dp, top: 0, right: 0, left: 0, bottom: 0) + static let defaultContentPosition = ContentPosition(gravity: defaultGravity, margin: defaultMargin) + } + + func filter(_ contentPosition: ContentPositionDTO?) throws -> ContentPosition { + guard let contentPosition = contentPosition else { + Logger.common(message: "Content position is invalid or missing. Default value set: [\(Constants.defaultContentPosition)].", level: .debug, category: .inAppMessages) + return Constants.defaultContentPosition + } + + var customGravity: ContentPositionGravity + if let gravity = contentPosition.gravity { + let vertical = gravity.vertical ?? .bottom + let horizontal = gravity.horizontal ?? .center + customGravity = ContentPositionGravity(vertical: vertical, horizontal: horizontal) + } else { + Logger.common(message: "Gravity is invalid or missing. Default value set: [\(Constants.defaultGravity)].", level: .debug, category: .inAppMessages) + customGravity = Constants.defaultGravity + } + + var customMargin: ContentPositionMargin? + if let margin = contentPosition.margin { + switch margin.kind { + case .dp: + if let top = margin.top, + let left = margin.left, + let right = margin.right, + let bottom = margin.bottom, + top >= 0, + left >= 0, + right >= 0, + bottom >= 0 { + customMargin = ContentPositionMargin(kind: margin.kind, top: top, right: right, left: left, bottom: bottom) + } + case .unknown: + Logger.common(message: "Content position margin kind is unknown. Default value set: [\(Constants.defaultMargin)].", level: .debug, category: .inAppMessages) + customMargin = Constants.defaultMargin + } + } else { + Logger.common(message: "Content position margin is invalid or missing. Default value set: [\(Constants.defaultMargin)].", level: .debug, category: .inAppMessages) + customMargin = Constants.defaultMargin + } + + guard let customMargin = customMargin else { + throw CustomDecodingError.unknownType("ContentPositionFilterService validation not passed. Inapp will be skipped.") + } + + return ContentPosition(gravity: customGravity, margin: customMargin) + } +} diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsColorFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsColorFilter.swift new file mode 100644 index 00000000..8de5a184 --- /dev/null +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsColorFilter.swift @@ -0,0 +1,29 @@ +// +// ElementsColorFilterService.swift +// Mindbox +// +// Created by vailence on 15.09.2023. +// Copyright © 2023 Mindbox. All rights reserved. +// + +import Foundation +import MindboxLogger + +protocol ElementsColorFilterProtocol { + func filter(_ color: String?) throws -> String +} + +final class ElementsColorFilterService: ElementsColorFilterProtocol { + enum Constants { + static let defaultColor = "#FFFFFF" + } + + func filter(_ color: String?) throws -> String { + guard let color = color, color.isHexValid() else { + Logger.common(message: "Color is invalid or missing. Default value set: [\(Constants.defaultColor)]", level: .debug, category: .inAppMessages) + return Constants.defaultColor + } + + return color + } +} diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsFilter.swift new file mode 100644 index 00000000..3091772e --- /dev/null +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsFilter.swift @@ -0,0 +1,70 @@ +// +// ElementsFilter.swift +// Mindbox +// +// Created by vailence on 07.09.2023. +// Copyright © 2023 Mindbox. All rights reserved. +// + +import Foundation +import MindboxLogger + +protocol ElementsFilterProtocol { + func filter(_ elements: [ContentElementDTO]?) throws -> [ContentElement] +} + +final class ElementsFilterService: ElementsFilterProtocol { + + enum Constants { + static let lineWidth = 2 + } + + private let sizeFilter: ElementsSizeFilterProtocol + private let positionFilter: ElementsPositionFilterProtocol + private let colorFilter: ElementsColorFilterProtocol + + init(sizeFilter: ElementsSizeFilterProtocol, positionFilter: ElementsPositionFilterProtocol, colorFilter: ElementsColorFilterProtocol) { + self.sizeFilter = sizeFilter + self.positionFilter = positionFilter + self.colorFilter = colorFilter + } + + func filter(_ elements: [ContentElementDTO]?) throws -> [ContentElement] { + guard let elements = elements, !elements.isEmpty else { + Logger.common(message: "Elements are missing or empty.", level: .debug, category: .inAppMessages) + return [] + } + + var filteredElements: [ContentElement] = [] + + elementsLoop: for element in elements { + if element.elementType == .unknown { + continue + } + + switch element { + case .closeButton(let closeButtonElementDTO): + let size = try sizeFilter.filter(closeButtonElementDTO.size) + let position = try positionFilter.filter(closeButtonElementDTO.position) + let color = try colorFilter.filter(closeButtonElementDTO.color?.element) + var lineWidth: Int + if let lineWidthDTO = closeButtonElementDTO.lineWidth?.element { + lineWidth = lineWidthDTO + } else { + lineWidth = Constants.lineWidth + Logger.common(message: "Line width is invalid or missing. Default value set: [\(Constants.lineWidth)].", level: .debug, category: .inAppMessages) + } + let customCloseButtonElement = CloseButtonElement(color: color, + lineWidth: lineWidth, + size: size, + position: position) + let element = try ContentElement(type: .closeButton, closeButton: customCloseButtonElement) + filteredElements.append(element) + case .unknown: + continue elementsLoop + } + } + + return filteredElements + } +} diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsPositionFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsPositionFilter.swift new file mode 100644 index 00000000..672d9a7c --- /dev/null +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsPositionFilter.swift @@ -0,0 +1,56 @@ +// +// ElementsPositionFilter.swift +// Mindbox +// +// Created by vailence on 07.09.2023. +// Copyright © 2023 Mindbox. All rights reserved. +// + +import Foundation +import MindboxLogger + +protocol ElementsPositionFilterProtocol { + func filter(_ position: ContentElementPositionDTO?) throws -> ContentElementPosition +} + +final class ElementsPositionFilterService: ElementsPositionFilterProtocol { + + enum Constants { + static let defaultMargin = ContentElementPositionMargin(kind: .proportion, top: 0.02, right: 0.02, left: 0.02, bottom: 0.02) + + } + + func filter(_ position: ContentElementPositionDTO?) throws -> ContentElementPosition { + guard let position = position, + let margin = position.margin else { + Logger.common(message: "Position or margin is invalid or missing. Default value set: [\(Constants.defaultMargin)].", level: .debug, category: .inAppMessages) + return ContentElementPosition(margin: Constants.defaultMargin) + } + + let marginRange: ClosedRange = 0...1 + + switch margin.kind { + case .proportion: + if let top = margin.top, + let left = margin.left, + let right = margin.right, + let bottom = margin.bottom, + marginRange.contains(top), + marginRange.contains(left), + marginRange.contains(right), + marginRange.contains(bottom) { + let customMargin = ContentElementPositionMargin(kind: margin.kind, + top: top, + right: right, + left: left, + bottom: bottom) + return ContentElementPosition(margin: customMargin) + } + case .unknown: + Logger.common(message: "Unknown type of ContentElementPosition. Default value set: [\(Constants.defaultMargin)].", level: .debug, category: .inAppMessages) + return ContentElementPosition(margin: Constants.defaultMargin) + } + + throw CustomDecodingError.unknownType("ElementsPositionFilterService validation not passed. In-app will be ignored.") + } +} diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsSizeFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsSizeFilter.swift new file mode 100644 index 00000000..3dd87127 --- /dev/null +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsSizeFilter.swift @@ -0,0 +1,42 @@ +// +// ElementsSizeFilter.swift +// Mindbox +// +// Created by vailence on 07.09.2023. +// Copyright © 2023 Mindbox. All rights reserved. +// + +import Foundation +import MindboxLogger + +protocol ElementsSizeFilterProtocol { + 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 { + guard let size = size else { + Logger.common(message: "Size is invalid or missing. Default value set: [\(Constants.defaultSize)].", level: .debug, category: .inAppMessages) + return Constants.defaultSize + } + + switch size.kind { + case .dp: + if let height = size.height, + let width = size.width, + height >= 0, + width >= 0 { + return ContentElementSize(kind: size.kind, width: width, height: height) + } + case .unknown: + Logger.common(message: "Unknown type of ContentElementSize. Default value set: [\(Constants.defaultSize)].", level: .debug, category: .inAppMessages) + return Constants.defaultSize + } + + throw CustomDecodingError.unknownType("ElementSizeFilterService validation not passed. In-app will be ignored.") + } +} diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/InappFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/InappFilter.swift new file mode 100644 index 00000000..a254e2ce --- /dev/null +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/InappFilter.swift @@ -0,0 +1,67 @@ +// +// InappFilter.swift +// Mindbox +// +// Created by vailence on 07.09.2023. +// Copyright © 2023 Mindbox. All rights reserved. +// + +import Foundation +import MindboxLogger + +protocol InappFilterProtocol { + func filter(inapps: [InAppDTO]?) -> [InApp] +} + +final class InappsFilterService: InappFilterProtocol { + private let variantsFilter: VariantFilterProtocol + private let sdkVersionNumeric = 8 + + init(variantsFilter: VariantFilterProtocol) { + self.variantsFilter = variantsFilter + } + + func filter(inapps: [InAppDTO]?) -> [InApp] { + 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 { + 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, + targeting: inapp.targeting, + form: formModel) + filteredInapps.append(inappModel) + } + } catch { + 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 + } +} diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayerActionFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayerActionFilter.swift new file mode 100644 index 00000000..ea6c0400 --- /dev/null +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayerActionFilter.swift @@ -0,0 +1,34 @@ +// +// LayerActionFilter.swift +// Mindbox +// +// Created by vailence on 07.09.2023. +// Copyright © 2023 Mindbox. All rights reserved. +// + +import Foundation + +protocol LayerActionFilterProtocol { + func filter(_ action: ContentBackgroundLayerActionDTO?) throws -> ContentBackgroundLayerAction +} + +final class LayerActionFilterService: LayerActionFilterProtocol { + func filter(_ action: ContentBackgroundLayerActionDTO?) throws -> ContentBackgroundLayerAction { + guard let action = action, + action.actionType != .unknown else { + throw CustomDecodingError.unknownType("LayerActionFilterService validation not passed.") + } + + switch action { + case .redirectUrl(let redirectUrlLayerAction): + if let value = redirectUrlLayerAction.value, let payload = redirectUrlLayerAction.intentPayload { + let redirectUrlLayerActionModel = RedirectUrlLayerAction(intentPayload: payload, value: value) + return try ContentBackgroundLayerAction(type: .redirectUrl, redirectModel: redirectUrlLayerActionModel) + } + case .unknown: + break + } + + throw CustomDecodingError.unknownType("LayerActionFilterService validation not passed.") + } +} diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayersFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayersFilter.swift new file mode 100644 index 00000000..a4eb6df3 --- /dev/null +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayersFilter.swift @@ -0,0 +1,52 @@ +// +// LayersFilter.swift +// Mindbox +// +// Created by vailence on 07.09.2023. +// Copyright © 2023 Mindbox. All rights reserved. +// + +import Foundation +import MindboxLogger + +protocol LayersFilterProtocol { + func filter(_ layers: [ContentBackgroundLayerDTO]?) throws -> [ContentBackgroundLayer] +} + +final class LayersFilterService: LayersFilterProtocol { + private let actionFilter: LayerActionFilterProtocol + private let sourceFilter: LayersSourceFilterProtocol + + init(actionFilter: LayerActionFilterProtocol, sourceFilter: LayersSourceFilterProtocol) { + self.actionFilter = actionFilter + self.sourceFilter = sourceFilter + } + + func filter(_ layers: [ContentBackgroundLayerDTO]?) throws -> [ContentBackgroundLayer] { + var filteredLayers: [ContentBackgroundLayer] = [] + + guard let layers = layers else { + throw CustomDecodingError.unknownType("LayersFilterService validation not passed.") + } + + for layer in layers { + switch layer { + case .image(let imageContentBackgroundLayerDTO): + 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: + Logger.common(message: "Unknown type of layer. Layer will be skipped.", level: .debug, category: .inAppMessages) + break + } + } + + if filteredLayers.isEmpty { + throw CustomDecodingError.unknownType("Layers cannot be empty. In-app will be skipped.") + } + + return filteredLayers.filter { $0.layerType != .unknown } + } +} diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayersSourceFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayersSourceFilter.swift new file mode 100644 index 00000000..65a0e5d7 --- /dev/null +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayersSourceFilter.swift @@ -0,0 +1,34 @@ +// +// LayersSourceFilter.swift +// Mindbox +// +// Created by vailence on 07.09.2023. +// Copyright © 2023 Mindbox. All rights reserved. +// + +import Foundation + +protocol LayersSourceFilterProtocol { + func filter(_ source: ContentBackgroundLayerSourceDTO?) throws -> ContentBackgroundLayerSource +} + +final class LayersSourceFilterService: LayersSourceFilterProtocol { + func filter(_ source: ContentBackgroundLayerSourceDTO?) throws -> ContentBackgroundLayerSource { + guard let source = source, + source.sourceType != .unknown else { + throw CustomDecodingError.unknownType("LayersSourceFilterService validation not passed.") + } + + switch source { + case .url(let urlLayerSource): + if let value = urlLayerSource.value, !value.isEmpty { + let urlLayerSourceModel = UrlLayerSource(value: value) + return try ContentBackgroundLayerSource(type: .url, urlModel: urlLayerSourceModel) + } + case .unknown: + break + } + + throw CustomDecodingError.unknownType("LayersSourceFilterService validation not passed.") + } +} diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/VariantsFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/VariantsFilter.swift new file mode 100644 index 00000000..d52c9476 --- /dev/null +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/VariantsFilter.swift @@ -0,0 +1,76 @@ +// +// VariantsFilter.swift +// Mindbox +// +// Created by vailence on 07.09.2023. +// Copyright © 2023 Mindbox. All rights reserved. +// + +import Foundation +import MindboxLogger + +protocol VariantFilterProtocol { + func filter(_ variants: [MindboxFormVariantDTO]?) throws -> [MindboxFormVariant] +} + +final class VariantFilterService: VariantFilterProtocol { + + private let layersFilter: LayersFilterProtocol + private let elementsFilter: ElementsFilterProtocol + private let contentPositionFilter: ContentPositionFilterProtocol + + init(layersFilter: LayersFilterProtocol, elementsFilter: ElementsFilterProtocol, contentPositionFilter: ContentPositionFilterProtocol) { + self.layersFilter = layersFilter + self.elementsFilter = elementsFilter + self.contentPositionFilter = contentPositionFilter + } + + func filter(_ variants: [MindboxFormVariantDTO]?) throws -> [MindboxFormVariant] { + var resultVariants: [MindboxFormVariant] = [] + guard let variants = variants else { + 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 { + throw CustomDecodingError.unknownType("VariantFilterService validation not passed.") + } + + let filteredLayers = try layersFilter.filter(background.layers) + let fileterdElements = try elementsFilter.filter(content.elements) + + let backgroundModel = ContentBackground(layers: filteredLayers) + + let contentModel = InappFormVariantContent(background: backgroundModel, elements: fileterdElements) + let modalFormVariantModel = ModalFormVariant(content: contentModel) + let mindboxFormVariant = try MindboxFormVariant(type: .modal, modalVariant: modalFormVariantModel) + resultVariants.append(mindboxFormVariant) + case .snackbar(let snackbarFormVariant): + guard let content = snackbarFormVariant.content, + let background = content.background else { + throw CustomDecodingError.unknownType("VariantFilterService validation not passed.") + } + + 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, + position: contentPosition, + elements: filteredElements) + let snackbarFormVariant = SnackbarFormVariant(content: contentModel) + let mindboxFormVariant = try MindboxFormVariant(type: .snackbar, snackbarVariant: snackbarFormVariant) + resultVariants.append(mindboxFormVariant) + case .unknown: + Logger.common(message: "Unknown type of variant. Variant will be skipped.", level: .debug, category: .inAppMessages) + continue + } + } + + return resultVariants + } +} diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/VariantImageUrlExtractorService.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/VariantImageUrlExtractorService.swift index bcbc3412..7876a33c 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/VariantImageUrlExtractorService.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/VariantImageUrlExtractorService.swift @@ -8,44 +8,43 @@ import Foundation -class VariantImageUrlExtractorService { - func extractImageURL(from variant: MindboxFormVariant) -> String? { - var urlString: String? +protocol VariantImageUrlExtractorServiceProtocol { + func extractImageURL(from variant: MindboxFormVariant) -> [String] +} + +class VariantImageUrlExtractorService: VariantImageUrlExtractorServiceProtocol { + func extractImageURL(from variant: MindboxFormVariant) -> [String] { + var urlString: [String] = [] + + let elements: [ContentBackgroundLayer] + switch variant { - case .modal(let modalModel): - let modalModel = modalModel.content.background.layers.elements.first(where: { - switch $0 { - case .image(let imageModel): - switch imageModel.source { - case .url(let urlModel): - urlString = urlModel.value - return true - case .unknown: - return false - } - case .unknown: - return false - } - }) - case .snackbar(let snackbarModel): - let snackbarModel = snackbarModel.content.background.layers.elements.first { - switch $0 { - case .image(let imageModel): - switch imageModel.source { - case .url(let urlModel): - urlString = urlModel.value - return true - case .unknown: - return false - } - case .unknown: - return false - } + case .modal(let modalModel): + elements = modalModel.content.background.layers + case .snackbar(let snackbarModel): + elements = snackbarModel.content.background.layers + case .unknown: + return [] + } + + extractImageURLs(from: elements, into: &urlString) + + return urlString + } + + private func extractImageURLs(from elements: [ContentBackgroundLayer], into urlString: inout [String]) { + for element in elements { + switch element { + case .image(let imageModel): + switch imageModel.source { + case .url(let urlModel): + urlString.append(urlModel.value) + case .unknown: + break } case .unknown: - return nil + break + } } - - return urlString } } diff --git a/Mindbox/InAppMessages/Models/Config/ConfigResponse.swift b/Mindbox/InAppMessages/Models/Config/ConfigResponse.swift index 301bf2a4..d6f39ad4 100644 --- a/Mindbox/InAppMessages/Models/Config/ConfigResponse.swift +++ b/Mindbox/InAppMessages/Models/Config/ConfigResponse.swift @@ -9,7 +9,7 @@ import Foundation import MindboxLogger struct ConfigResponse: Decodable { - let inapps: FailableDecodableArray? + let inapps: FailableDecodableArray? let monitoring: Monitoring? let settings: Settings? let abtests: [ABTest]? @@ -21,7 +21,7 @@ struct ConfigResponse: Decodable { init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) - inapps = try? container.decodeIfPresent(FailableDecodableArray.self, forKey: .inapps) + inapps = try? container.decodeIfPresent(FailableDecodableArray.self, forKey: .inapps) monitoring = ConfigResponse.decodeIfPresent(container, forKey: .monitoring, errorDesc: "Cannot decode Monitoring") settings = ConfigResponse.decodeIfPresent(container, forKey: .settings, errorDesc: "Cannot decode Settings") @@ -46,7 +46,7 @@ struct ConfigResponse: Decodable { } } - init(inapps: FailableDecodableArray? = nil, monitoring: Monitoring? = nil, settings: Settings? = nil, abtests: [ABTest]? = nil) { + init(inapps: FailableDecodableArray? = nil, monitoring: Monitoring? = nil, settings: Settings? = nil, abtests: [ABTest]? = nil) { self.inapps = inapps self.monitoring = monitoring self.settings = settings diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InAppModel.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InAppModel.swift index 90dfc1ac..2aaa51b5 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InAppModel.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InAppModel.swift @@ -8,28 +8,16 @@ import Foundation +struct InAppDTO: Decodable, Equatable { + let id: String + let sdkVersion: SdkVersion + let targeting: Targeting + let form: InAppFormDTO +} + struct InApp: Decodable, Equatable { let id: String let sdkVersion: SdkVersion let targeting: Targeting let form: InAppForm - - enum CodingKeys: String, CodingKey { - case id - case sdkVersion - case targeting - case form - } - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - id = try container.decode(String.self, forKey: .id) - sdkVersion = try container.decode(SdkVersion.self, forKey: .sdkVersion) - targeting = try container.decode(Targeting.self, forKey: .targeting) - form = try container.decode(InAppForm.self, forKey: .form) - - if !InappValidator().isValid(item: self) { - throw CustomDecodingError.decodingError("The inapp not passed validation. The inapp will be ignored.") - } - } } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappForm.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappForm.swift index af730dc1..64dd16d7 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappForm.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappForm.swift @@ -8,21 +8,10 @@ import Foundation +struct InAppFormDTO: Decodable, Equatable { + let variants: [MindboxFormVariantDTO]? +} + struct InAppForm: Decodable, Equatable { - let variants: FailableDecodableArray - - enum CodingKeys: String, CodingKey { - case variants - } - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - let variants = try container.decode(FailableDecodableArray.self, forKey: .variants) - - if variants.elements.isEmpty { - throw CustomDecodingError.decodingError("Variants array cannot be empty.") - } - - self.variants = variants - } + let variants: [MindboxFormVariant] } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackground.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackground.swift index 66158672..3920b855 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackground.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackground.swift @@ -8,25 +8,10 @@ import Foundation +struct ContentBackgroundDTO: Decodable, Equatable { + let layers: [ContentBackgroundLayerDTO]? +} + struct ContentBackground: Decodable, Equatable { - let layers: FailableDecodableArray - - enum CodingKeys: String, CodingKey { - case layers - } - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - let layers = try container.decode(FailableDecodableArray.self, forKey: .layers) - - if layers.elements.isEmpty { - throw DecodingError.dataCorruptedError( - forKey: .layers, - in: container, - debugDescription: "Layers cannot be empty." - ) - } - - self.layers = layers - } + let layers: [ContentBackgroundLayer] } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundLayer.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundLayer.swift index 6e285c81..c0c3a907 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundLayer.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundLayer.swift @@ -21,6 +21,59 @@ enum ContentBackgroundLayerType: String, Decodable { } } +enum ContentBackgroundLayerDTO: Decodable, Hashable, Equatable { + case image(ImageContentBackgroundLayerDTO) + case unknown + + enum CodingKeys: String, CodingKey { + case type = "$type" + } + + static func == (lhs: ContentBackgroundLayerDTO, rhs: ContentBackgroundLayerDTO) -> Bool { + switch (lhs, rhs) { + case (.image, .image): return true + case (.unknown, .unknown): return true + default: return false + } + } + + func hash(into hasher: inout Hasher) { + switch self { + case .image: hasher.combine("image") + case .unknown: hasher.combine("unknown") + } + } + + init(from decoder: Decoder) throws { + let container: KeyedDecodingContainer = try decoder.container( + keyedBy: CodingKeys.self) + guard let type = try? container.decode(ContentBackgroundLayerType.self, forKey: .type) else { + throw CustomDecodingError.decodingError("The layer type could not be decoded. The layer will be ignored.") + } + + let layerContainer: SingleValueDecodingContainer = try decoder.singleValueContainer() + + switch type { + case .image: + let imageLayer = try layerContainer.decode(ImageContentBackgroundLayerDTO.self) + self = .image(imageLayer) + case .unknown: + self = .unknown + } + } +} + +extension ContentBackgroundLayerDTO { + var layerType: ContentBackgroundLayerType { + switch self { + case .image: + return .image + case .unknown: + return .unknown + } + } +} + enum ContentBackgroundLayer: Decodable, Hashable, Equatable { case image(ImageContentBackgroundLayer) case unknown @@ -58,7 +111,7 @@ enum ContentBackgroundLayer: Decodable, Hashable, Equatable { let imageLayer = try layerContainer.decode(ImageContentBackgroundLayer.self) self = .image(imageLayer) case .unknown: - throw CustomDecodingError.unknownType("The layer type is unrecognized. The action will be ignored.") + self = .unknown } } } @@ -73,3 +126,17 @@ extension ContentBackgroundLayer { } } } + +extension ContentBackgroundLayer { + init(type: ContentBackgroundLayerType, imageLayer: ImageContentBackgroundLayer? = nil) throws { + switch type { + case .image: + guard let imageLayer = imageLayer else { + throw CustomDecodingError.unknownType("The variant type could not be decoded. The variant will be ignored.") + } + self = .image(imageLayer) + case .unknown: + self = .unknown + } + } +} diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundLayerAction/Actions/RedirectUrlLayerAction.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundLayerAction/Actions/RedirectUrlLayerAction.swift index 2ad5caac..6d8a76a2 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundLayerAction/Actions/RedirectUrlLayerAction.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundLayerAction/Actions/RedirectUrlLayerAction.swift @@ -8,8 +8,12 @@ import Foundation +struct RedirectUrlLayerActionDTO: ContentBackgroundLayerActionProtocol { + let intentPayload: String? + let value: String? +} + struct RedirectUrlLayerAction: ContentBackgroundLayerActionProtocol { let intentPayload: String let value: String } - diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundLayerAction/ContentBackgroundLayerAction.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundLayerAction/ContentBackgroundLayerAction.swift index e1341d29..86925131 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundLayerAction/ContentBackgroundLayerAction.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundLayerAction/ContentBackgroundLayerAction.swift @@ -21,6 +21,59 @@ enum ContentBackgroundLayerActionType: String, Decodable { } } +enum ContentBackgroundLayerActionDTO: Decodable, Hashable, Equatable { + case redirectUrl(RedirectUrlLayerActionDTO) + case unknown + + enum CodingKeys: String, CodingKey { + case type = "$type" + } + + static func == (lhs: ContentBackgroundLayerActionDTO, rhs: ContentBackgroundLayerActionDTO) -> Bool { + switch (lhs, rhs) { + case (.redirectUrl, .redirectUrl): return true + case (.unknown, .unknown): return true + default: return false + } + } + + func hash(into hasher: inout Hasher) { + switch self { + case .redirectUrl: hasher.combine("redirectUrl") + case .unknown: hasher.combine("unknown") + } + } + + init(from decoder: Decoder) throws { + let container: KeyedDecodingContainer = try decoder.container( + keyedBy: CodingKeys.self) + guard let type = try? container.decode(ContentBackgroundLayerActionType.self, forKey: .type) else { + throw CustomDecodingError.decodingError("The action type could not be decoded. The action will be ignored.") + } + + let actionContainer: SingleValueDecodingContainer = try decoder.singleValueContainer() + + switch type { + case .redirectUrl: + let redirectUrlAction = try actionContainer.decode(RedirectUrlLayerActionDTO.self) + self = .redirectUrl(redirectUrlAction) + case .unknown: + self = .unknown + } + } +} + +extension ContentBackgroundLayerActionDTO { + var actionType: ContentBackgroundLayerActionType { + switch self { + case .redirectUrl: + return .redirectUrl + case .unknown: + return .unknown + } + } +} + enum ContentBackgroundLayerAction: Decodable, Hashable, Equatable { case redirectUrl(RedirectUrlLayerAction) case unknown @@ -58,7 +111,7 @@ enum ContentBackgroundLayerAction: Decodable, Hashable, Equatable { let redirectUrlAction = try actionContainer.decode(RedirectUrlLayerAction.self) self = .redirectUrl(redirectUrlAction) case .unknown: - throw CustomDecodingError.unknownType("The action type could not be decoded. The action will be ignored.") + self = .unknown } } } @@ -73,3 +126,17 @@ extension ContentBackgroundLayerAction { } } } + +extension ContentBackgroundLayerAction { + init(type: ContentBackgroundLayerActionType, redirectModel: RedirectUrlLayerAction? = nil) throws { + switch type { + case .redirectUrl: + guard let redirectModel = redirectModel else { + throw CustomDecodingError.unknownType("The variant type could not be decoded. The variant will be ignored.") + } + self = .redirectUrl(redirectModel) + case .unknown: + self = .unknown + } + } +} diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundSource/ContentBackgroundLayerSource.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundSource/ContentBackgroundLayerSource.swift index 5050aea2..8f0c58de 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundSource/ContentBackgroundLayerSource.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundSource/ContentBackgroundLayerSource.swift @@ -22,6 +22,59 @@ enum ContentBackgroundLayerSourceType: String, Decodable { } } +enum ContentBackgroundLayerSourceDTO: Decodable, Hashable, Equatable { + case url(UrlLayerSourceDTO) + case unknown + + enum CodingKeys: String, CodingKey { + case type = "$type" + } + + static func == (lhs: ContentBackgroundLayerSourceDTO, rhs: ContentBackgroundLayerSourceDTO) -> Bool { + switch (lhs, rhs) { + case (.url, .url): return true + case (.unknown, .unknown): return true + default: return false + } + } + + func hash(into hasher: inout Hasher) { + switch self { + case .url: hasher.combine("url") + case .unknown: hasher.combine("unknown") + } + } + + init(from decoder: Decoder) throws { + let container: KeyedDecodingContainer = try decoder.container( + keyedBy: CodingKeys.self) + guard let type = try? container.decode(ContentBackgroundLayerSourceType.self, forKey: .type) else { + throw CustomDecodingError.decodingError("The source type could not be decoded. The source will be ignored.") + } + + let sourceContainer: SingleValueDecodingContainer = try decoder.singleValueContainer() + + switch type { + case .url: + let urlSource = try sourceContainer.decode(UrlLayerSourceDTO.self) + self = .url(urlSource) + case .unknown: + self = .unknown + } + } +} + +extension ContentBackgroundLayerSourceDTO { + var sourceType: ContentBackgroundLayerSourceType { + switch self { + case .url: + return .url + case .unknown: + return .unknown + } + } +} + enum ContentBackgroundLayerSource: Decodable, Hashable, Equatable { case url(UrlLayerSource) case unknown @@ -59,7 +112,7 @@ enum ContentBackgroundLayerSource: Decodable, Hashable, Equatable { let urlSource = try sourceContainer.decode(UrlLayerSource.self) self = .url(urlSource) case .unknown: - throw CustomDecodingError.unknownType("The source type could not be decoded. The source will be ignored.") + self = .unknown } } } @@ -74,3 +127,17 @@ extension ContentBackgroundLayerSource { } } } + +extension ContentBackgroundLayerSource { + init(type: ContentBackgroundLayerSourceType, urlModel: UrlLayerSource? = nil) throws { + switch type { + case .url: + guard let urlModel = urlModel else { + throw CustomDecodingError.unknownType("The variant type could not be decoded. The variant will be ignored.") + } + self = .url(urlModel) + case .unknown: + self = .unknown + } + } +} diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundSource/Sources/UrlLayerSource.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundSource/Sources/UrlLayerSource.swift index db3c920f..7bf0df5d 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundSource/Sources/UrlLayerSource.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundSource/Sources/UrlLayerSource.swift @@ -8,6 +8,10 @@ import Foundation +struct UrlLayerSourceDTO: ContentBackgroundLayerSourceProtocol { + let value: String? +} + struct UrlLayerSource: ContentBackgroundLayerSourceProtocol { let value: String } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/Layers/ImageContentBackgroundLayer.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/Layers/ImageContentBackgroundLayer.swift index e55edf39..dca5190f 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/Layers/ImageContentBackgroundLayer.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/Layers/ImageContentBackgroundLayer.swift @@ -8,6 +8,12 @@ import Foundation +struct ImageContentBackgroundLayerDTO: ContentBackgroundLayerProtocol { + let action: ContentBackgroundLayerActionDTO? + let source: ContentBackgroundLayerSourceDTO? +} + + struct ImageContentBackgroundLayer: ContentBackgroundLayerProtocol { let action: ContentBackgroundLayerAction let source: ContentBackgroundLayerSource diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElement.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElement.swift index 1a5eac1b..8c802b9d 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElement.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElement.swift @@ -21,6 +21,59 @@ enum ContentElementType: String, Decodable { } } +enum ContentElementDTO: Decodable, Hashable, Equatable { + case closeButton(CloseButtonElementDTO) + case unknown + + enum CodingKeys: String, CodingKey { + case type = "$type" + } + + static func == (lhs: ContentElementDTO, rhs: ContentElementDTO) -> Bool { + switch (lhs, rhs) { + case (.closeButton, .closeButton): return true + case (.unknown, .unknown): return true + default: return false + } + } + + func hash(into hasher: inout Hasher) { + switch self { + case .closeButton: hasher.combine("closeButton") + case .unknown: hasher.combine("unknown") + } + } + + init(from decoder: Decoder) throws { + let container: KeyedDecodingContainer = try decoder.container( + keyedBy: CodingKeys.self) + guard let type = try? container.decode(ContentElementType.self, forKey: .type) else { + throw CustomDecodingError.decodingError("The variant type could not be decoded. The variant will be ignored.") + } + + let elementContainer: SingleValueDecodingContainer = try decoder.singleValueContainer() + + switch type { + case .closeButton: + let closeButtonElement = try elementContainer.decode(CloseButtonElementDTO.self) + self = .closeButton(closeButtonElement) + case .unknown: + self = .unknown + } + } +} + +extension ContentElementDTO { + var elementType: ContentElementType { + switch self { + case .closeButton: + return .closeButton + case .unknown: + return .unknown + } + } +} + enum ContentElement: Decodable, Hashable, Equatable { case closeButton(CloseButtonElement) case unknown @@ -58,7 +111,7 @@ enum ContentElement: Decodable, Hashable, Equatable { let closeButtonElement = try elementContainer.decode(CloseButtonElement.self) self = .closeButton(closeButtonElement) case .unknown: - throw CustomDecodingError.unknownType("The variant type could not be decoded. The variant will be ignored.") + self = .unknown } } } @@ -73,3 +126,17 @@ extension ContentElement { } } } + +extension ContentElement { + init(type: ContentElementType, closeButton: CloseButtonElement? = nil) throws { + switch type { + case .closeButton: + guard let closeButtonModel = closeButton else { + throw CustomDecodingError.unknownType("The variant type could not be decoded. The variant will be ignored.") + } + self = .closeButton(closeButtonModel) + case .unknown: + self = .unknown + } + } +} diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPosition.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPosition.swift index 1358a12b..1f644a14 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPosition.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPosition.swift @@ -8,6 +8,11 @@ import Foundation +struct ContentElementPositionDTO: Decodable, Equatable { + let margin: ContentElementPositionMarginDTO? +} + + struct ContentElementPosition: Decodable, Equatable { - let margin: FailableDecodable? + let margin: ContentElementPositionMargin } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPositionMargin/ContentElementPositionMargin.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPositionMargin/ContentElementPositionMargin.swift index 50addb0d..f9b560f9 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPositionMargin/ContentElementPositionMargin.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPositionMargin/ContentElementPositionMargin.swift @@ -8,40 +8,29 @@ import Foundation -struct ContentElementPositionMargin: Decodable, Equatable { - let kind: PositionMarginKind +struct ContentElementPositionMarginDTO: Decodable, Equatable { + let kind: ElementPositionMarginKind let top: Double? let right: Double? let left: Double? let bottom: Double? - - enum CodingKeys: CodingKey { - case kind - case top - case right - case left - case bottom - } +} + +struct ContentElementPositionMargin: Decodable, Equatable { + let kind: ElementPositionMarginKind + let top: Double + let right: Double + let left: Double + let bottom: Double +} + +enum ElementPositionMarginKind: String, Decodable, Equatable { + case proportion + case unknown init(from decoder: Decoder) throws { - let container: KeyedDecodingContainer = try decoder.container(keyedBy: ContentElementPositionMargin.CodingKeys.self) - - self.kind = try container.decode(PositionMarginKind.self, forKey: ContentElementPositionMargin.CodingKeys.kind) - self.top = try container.decodeIfPresentSafely(Double.self, forKey: ContentElementPositionMargin.CodingKeys.top) - self.right = try container.decodeIfPresentSafely(Double.self, forKey: ContentElementPositionMargin.CodingKeys.right) - self.left = try container.decodeIfPresentSafely(Double.self, forKey: ContentElementPositionMargin.CodingKeys.left) - self.bottom = try container.decodeIfPresentSafely(Double.self, forKey: ContentElementPositionMargin.CodingKeys.bottom) - - if !ContentElementPositionMarginValidator().isValid(item: self) { - throw CustomDecodingError.decodingError("ContentElementPositionMargin not passed validation. It will be ignored.") - } - } - - init(kind: PositionMarginKind, top: Double? = nil, right: Double? = nil, left: Double? = nil, bottom: Double? = nil) { - self.kind = kind - self.top = top - self.right = right - self.left = left - self.bottom = bottom + let container = try decoder.singleValueContainer() + let rawValue = try container.decode(RawValue.self) + self = ElementPositionMarginKind(rawValue: rawValue) ?? .unknown } } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPositionMargin/ContentElementPositionMarginValidator.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPositionMargin/ContentElementPositionMarginValidator.swift deleted file mode 100644 index 851a1610..00000000 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPositionMargin/ContentElementPositionMarginValidator.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// ContentElementPositionMarginValidator.swift -// Mindbox -// -// Created by vailence on 04.08.2023. -// Copyright © 2023 Mindbox. All rights reserved. -// - -import Foundation - -class ContentElementPositionMarginValidator: Validator { - typealias T = ContentElementPositionMargin - - func isValid(item: ContentElementPositionMargin) -> Bool { - if item.kind == .unknown { - return false - } - - return isValidRange(value: item.top) && isValidRange(value: item.right) - } - - func isValidRange(value: Double?) -> Bool { - guard let value = value else { - return false - } - - return value >= 0 && value <= 1 - } -} diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPositionMargin/PositionMarginKind/PositionMarginKind.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPositionMargin/PositionMarginKind/PositionMarginKind.swift deleted file mode 100644 index c860330a..00000000 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPositionMargin/PositionMarginKind/PositionMarginKind.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// PositionMarginKind.swift -// Mindbox -// -// Created by vailence on 04.08.2023. -// Copyright © 2023 Mindbox. All rights reserved. -// - -import Foundation - -enum PositionMarginKind: String, Decodable, Equatable { - case proportion - case unknown - - init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - let rawValue = try container.decode(RawValue.self) - self = PositionMarginKind(rawValue: rawValue) ?? .unknown - } -} diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementSize/ContentElementSize.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementSize/ContentElementSize.swift index 189d4468..d695d133 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementSize/ContentElementSize.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementSize/ContentElementSize.swift @@ -8,31 +8,14 @@ import Foundation +struct ContentElementSizeDTO: Decodable, Equatable { + let kind: ContentElementSizeKind + let width: Double? + let height: Double? +} + struct ContentElementSize: Decodable, Equatable { let kind: ContentElementSizeKind let width: Double let height: Double - - enum CodingKeys: String, CodingKey { - case kind - case width - case height - } - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - kind = try container.decode(ContentElementSizeKind.self, forKey: .kind) - width = try container.decode(Double.self, forKey: .width) - height = try container.decode(Double.self, forKey: .height) - - if !ContentElementSizeValidator().isValid(item: self) { - throw CustomDecodingError.decodingError("Content element size validation not passed.") - } - } - - init(kind: ContentElementSizeKind, width: Double, height: Double) { - self.kind = kind - self.width = width - self.height = height - } } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementSize/ContentElementSizeValidator.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementSize/ContentElementSizeValidator.swift deleted file mode 100644 index ad3c9cee..00000000 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementSize/ContentElementSizeValidator.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// ContentElementSizeValidator.swift -// Mindbox -// -// Created by vailence on 11.08.2023. -// Copyright © 2023 Mindbox. All rights reserved. -// - -import Foundation -import MindboxLogger - -class ContentElementSizeValidator: Validator { - typealias T = ContentElementSize - - func isValid(item: ContentElementSize) -> Bool { - guard item.width > 0 else { - Logger.common(message: "Content element size width is negative. Width: [\(item.width)", level: .error, category: .inAppMessages) - return false - - } - guard item.height > 0 else { - Logger.common(message: "Content element size height is negative. Height: [\(item.height)", level: .error, category: .inAppMessages) - return false - } - - return true - } -} diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/Elements/CloseButtonElement.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/Elements/CloseButtonElement.swift index 43ca3b35..31a38e68 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/Elements/CloseButtonElement.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/Elements/CloseButtonElement.swift @@ -8,9 +8,16 @@ import Foundation +struct CloseButtonElementDTO: ContentElementProtocol { + let color: FailableDecodable? + let lineWidth: FailableDecodable? + let size: ContentElementSizeDTO? + let position: ContentElementPositionDTO? +} + struct CloseButtonElement: ContentElementProtocol { - let color: String? - let lineWidth: Int? - let size: FailableDecodable? - let position: ContentElementPosition? + let color: String + let lineWidth: Int + let size: ContentElementSize + let position: ContentElementPosition } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPosition.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPosition.swift index 2bc48a9b..2b9cf74d 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPosition.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPosition.swift @@ -8,17 +8,12 @@ import Foundation +struct ContentPositionDTO: Decodable, Equatable { + let gravity: ContentPositionGravityDTO? + let margin: ContentPositionMarginDTO? +} + struct ContentPosition: Decodable, Equatable { - let gravity: FailableDecodable? - let margin: FailableDecodable? - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - gravity = try container.decodeIfPresent(FailableDecodable.self, forKey: .gravity) - margin = try container.decodeIfPresent(FailableDecodable.self, forKey: .margin) - } - - enum CodingKeys: String, CodingKey { - case gravity, margin - } + let gravity: ContentPositionGravity? + let margin: ContentPositionMargin } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPositionGravity/ContentPositionGravity.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPositionGravity/ContentPositionGravity.swift index 0297f09a..2dfa92de 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPositionGravity/ContentPositionGravity.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPositionGravity/ContentPositionGravity.swift @@ -8,49 +8,24 @@ import Foundation +struct ContentPositionGravityDTO: Decodable, Equatable { + let vertical: GravityVerticalType? + let horizontal: GravityHorizontalType? +} + struct ContentPositionGravity: Decodable, Equatable { - let vertical: VerticalType? - let horizontal: HorizontalType? - - enum HorizontalType: String, Decodable { - case left - case right - case center - case unknown - - init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - let rawValue = try container.decode(RawValue.self) - self = HorizontalType(rawValue: rawValue) ?? .unknown - } - } - - enum VerticalType: String, Decodable { - case top - case bottom - case center - case unknown - - init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - let rawValue = try container.decode(RawValue.self) - self = VerticalType(rawValue: rawValue) ?? .unknown - } - } - - enum CodingKeys: CodingKey { - case vertical - case horizontal - } - - init(from decoder: Decoder) throws { - let container: KeyedDecodingContainer = try decoder.container(keyedBy: ContentPositionGravity.CodingKeys.self) - - self.vertical = try container.decodeIfPresent(ContentPositionGravity.VerticalType.self, forKey: .vertical) - self.horizontal = try container.decodeIfPresent(ContentPositionGravity.HorizontalType.self, forKey: .horizontal) - - if vertical == .unknown || horizontal == .unknown { - throw CustomDecodingError.unknownType("") - } - } + let vertical: GravityVerticalType? + let horizontal: GravityHorizontalType? +} + +enum GravityHorizontalType: String, Decodable { + case left + case right + case center +} + +enum GravityVerticalType: String, Decodable { + case top + case bottom + case center } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPositionMargin/ContentPositionMargin.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPositionMargin/ContentPositionMargin.swift index 8781bf6b..2c0ada89 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPositionMargin/ContentPositionMargin.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPositionMargin/ContentPositionMargin.swift @@ -8,40 +8,29 @@ import Foundation -struct ContentPositionMargin: Decodable, Equatable { - let kind: PositionMarginKind +struct ContentPositionMarginDTO: Decodable, Equatable { + let kind: ContentPositionMarginKind let top: Double? let right: Double? let left: Double? let bottom: Double? +} + +struct ContentPositionMargin: Decodable, Equatable { + let kind: ContentPositionMarginKind + let top: Double + let right: Double + let left: Double + let bottom: Double +} + +enum ContentPositionMarginKind: String, Decodable, Equatable { + case dp + case unknown - enum CodingKeys: CodingKey { - case kind - case top - case right - case left - case bottom - } - - init(from decoder: Decoder, gravity: ContentPositionGravity) throws { - let container: KeyedDecodingContainer = try decoder.container(keyedBy: ContentPositionMargin.CodingKeys.self) - - self.kind = try container.decode(PositionMarginKind.self, forKey: .kind) - self.top = try container.decodeIfPresentSafely(Double.self, forKey: .top) - self.right = try container.decodeIfPresentSafely(Double.self, forKey: .right) - self.left = try container.decodeIfPresentSafely(Double.self, forKey: .left) - self.bottom = try container.decodeIfPresentSafely(Double.self, forKey: .bottom) - - if !ContentPositionMarginValidator().isValid(item: self) { - throw CustomDecodingError.decodingError("ContentPositionMargin not passed validation. It will be ignored.") - } - } - - init(kind: PositionMarginKind, top: Double? = nil, right: Double? = nil, left: Double? = nil, bottom: Double? = nil) { - self.kind = kind - self.top = top - self.right = right - self.left = left - self.bottom = bottom + init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + let rawValue = try container.decode(RawValue.self) + self = ContentPositionMarginKind(rawValue: rawValue) ?? .unknown } } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPositionMargin/ContentPositionMarginValidator.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPositionMargin/ContentPositionMarginValidator.swift deleted file mode 100644 index 3bb5923b..00000000 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPositionMargin/ContentPositionMarginValidator.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// ContentPositionMarginValidator.swift -// Mindbox -// -// Created by vailence on 14.08.2023. -// Copyright © 2023 Mindbox. All rights reserved. -// - -import Foundation - -class ContentPositionMarginValidator: Validator { - - typealias T = ContentPositionMargin - - func isValid(item: ContentPositionMargin) -> Bool { - if item.kind == .unknown { - return false - } - - return true - } -} diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/InappFormVariantContent.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/InappFormVariantContent.swift index 03ad7cf5..6db2730f 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/InappFormVariantContent.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/InappFormVariantContent.swift @@ -8,7 +8,12 @@ import Foundation +struct InappFormVariantContentDTO: Decodable, Equatable { + let background: ContentBackgroundDTO? + let elements: [ContentElementDTO]? +} + struct InappFormVariantContent: Decodable, Equatable { let background: ContentBackground - let elements: FailableDecodableArray? + let elements: [ContentElement]? } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/SnackbarFormVariantContent.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/SnackbarFormVariantContent.swift index 3c1dfadc..9c55610b 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/SnackbarFormVariantContent.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/SnackbarFormVariantContent.swift @@ -8,8 +8,14 @@ import Foundation +struct SnackbarFormVariantContentDTO: Decodable, Equatable { + let background: ContentBackgroundDTO? + let position: ContentPositionDTO? + let elements: [ContentElementDTO]? +} + struct SnackbarFormVariantContent: Decodable, Equatable { let background: ContentBackground - let position: ContentPosition? - let elements: FailableDecodableArray? + let position: ContentPosition + let elements: [ContentElement] } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/Variants/ModalFormVariant.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/Variants/ModalFormVariant.swift index a37bb2e9..75438e65 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/Variants/ModalFormVariant.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/Variants/ModalFormVariant.swift @@ -7,6 +7,10 @@ import Foundation +struct ModalFormVariantDTO: iFormVariant, Decodable, Equatable { + let content: InappFormVariantContentDTO? +} + struct ModalFormVariant: iFormVariant, Decodable, Equatable { let content: InappFormVariantContent } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/Variants/SnackbarFormVariant.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/Variants/SnackbarFormVariant.swift index f27c61eb..198247b8 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/Variants/SnackbarFormVariant.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/Variants/SnackbarFormVariant.swift @@ -8,6 +8,10 @@ import Foundation +struct SnackbarFormVariantDTO: iFormVariant, Decodable, Equatable { + let content: SnackbarFormVariantContentDTO? +} + struct SnackbarFormVariant: iFormVariant, Decodable, Equatable { let content: SnackbarFormVariantContent } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/iFormVariant.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/iFormVariant.swift index 368f0a3f..8a95948d 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/iFormVariant.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/iFormVariant.swift @@ -22,6 +22,54 @@ enum MindboxFormVariantType: String, Decodable { } } +enum MindboxFormVariantDTO: Decodable, Hashable, Equatable { + case modal(ModalFormVariantDTO) + case snackbar(SnackbarFormVariantDTO) + case unknown + + enum CodingKeys: String, CodingKey { + case type = "$type" + } + + static func == (lhs: MindboxFormVariantDTO, rhs: MindboxFormVariantDTO) -> Bool { + switch (lhs, rhs) { + case (.modal, .modal): return true + case (.snackbar, .snackbar): return true + case (.unknown, .unknown): return true + default: return false + } + } + + func hash(into hasher: inout Hasher) { + switch self { + case .modal: hasher.combine("modal") + case .snackbar: hasher.combine("snackbar") + case .unknown: hasher.combine("unknown") + } + } + + init(from decoder: Decoder) throws { + let container: KeyedDecodingContainer = try decoder.container( + keyedBy: CodingKeys.self) + guard let type = try? container.decode(MindboxFormVariantType.self, forKey: .type) else { + throw CustomDecodingError.decodingError("The variant type could not be decoded. The variant will be ignored.") + } + + let variantContainer: SingleValueDecodingContainer = try decoder.singleValueContainer() + + switch type { + case .modal: + let modalVariant = try variantContainer.decode(ModalFormVariantDTO.self) + self = .modal(modalVariant) + case .snackbar: + let snackbarVariant = try variantContainer.decode(SnackbarFormVariantDTO.self) + self = .snackbar(snackbarVariant) + case .unknown: + self = .unknown + } + } +} + enum MindboxFormVariant: Decodable, Hashable, Equatable { case modal(ModalFormVariant) case snackbar(SnackbarFormVariant) @@ -65,7 +113,29 @@ enum MindboxFormVariant: Decodable, Hashable, Equatable { let snackbarVariant = try variantContainer.decode(SnackbarFormVariant.self) self = .snackbar(snackbarVariant) case .unknown: + self = .unknown + throw CustomDecodingError.unknownType("The variant type could not be decoded. The variant will be ignored.") + } + } +} + +extension MindboxFormVariant { + init(type: MindboxFormVariantType, modalVariant: ModalFormVariant? = nil, snackbarVariant: SnackbarFormVariant? = nil) throws { + switch type { + case .modal: + guard let modalVariant = modalVariant else { + throw CustomDecodingError.unknownType("The variant type could not be decoded. The variant will be ignored.") + } + self = .modal(modalVariant) + + case .snackbar: + guard let snackbarVariant = snackbarVariant else { throw CustomDecodingError.unknownType("The variant type could not be decoded. The variant will be ignored.") + } + self = .snackbar(snackbarVariant) + + case .unknown: + self = .unknown } } } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappValidator.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappValidator.swift deleted file mode 100644 index 9fea5641..00000000 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappValidator.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// InappValidator.swift -// Mindbox -// -// Created by vailence on 03.08.2023. -// Copyright © 2023 Mindbox. All rights reserved. -// - -import Foundation -import MindboxLogger - -class InappValidator: Validator { - typealias T = InApp - - private let sdkVersionValidator: SDKVersionValidator - - init() { - self.sdkVersionValidator = SDKVersionValidator(sdkVersionNumeric: Constants.Versions.sdkVersionNumeric) - } - - func isValid(item: InApp) -> Bool { - if item.id.isEmpty { - Logger.common(message: "In-app id cannot be empty. In-app will be ignored.", level: .error, category: .inAppMessages) - return false - } - - if !sdkVersionValidator.isValid(item: item.sdkVersion) { - Logger.common(message: "Invalid SDK version for In-app. In-app with id \(item.id) will be ignored.", level: .error, category: .inAppMessages) - return false - } - - return true - } -} diff --git a/Mindbox/InAppMessages/Models/InAppFormData.swift b/Mindbox/InAppMessages/Models/InAppFormData.swift index fb19ebfd..942b4f41 100644 --- a/Mindbox/InAppMessages/Models/InAppFormData.swift +++ b/Mindbox/InAppMessages/Models/InAppFormData.swift @@ -12,7 +12,8 @@ import UIKit /// Domain model that contains all data needed to show inapp on screen struct InAppFormData { let inAppId: String - let image: UIImage + let imagesDict: [String: UIImage] + let firstImageValue: String let content: MindboxFormVariant } diff --git a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift index a8cf485f..165416fd 100644 --- a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift +++ b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift @@ -16,7 +16,7 @@ final class PresentationDisplayUseCase { private var model: InAppFormData? private var factory: ViewFactoryProtocol? private var tracker: InAppMessagesTrackerProtocol - + init(tracker: InAppMessagesTrackerProtocol) { self.tracker = tracker } @@ -26,10 +26,12 @@ final class PresentationDisplayUseCase { changeType(model: model.content) guard let window = presentationStrategy?.getWindow() else { - Logger.common(message: "In-app modal window creating failed") + Logger.common(message: "In-app window creating failed") return } + Logger.common(message: "PresentationDisplayUseCase window: \(window)") + guard let factory = self.factory else { Logger.common(message: "Factory does not exists.", level: .error, category: .general) return @@ -37,7 +39,8 @@ final class PresentationDisplayUseCase { guard let viewController = factory.create(model: model.content, id: model.inAppId, - image: model.image, + imagesDict: model.imagesDict, + firstImageValue: model.firstImageValue, onPresented: onPresented, onTapAction: onTapAction, onClose: onClose) else { @@ -45,6 +48,11 @@ final class PresentationDisplayUseCase { } presentedVC = viewController + + if let image = model.imagesDict[model.firstImageValue] { + presentationStrategy?.setupWindowFrame(model: model.content, imageSize: image.size) + } + presentationStrategy?.present(id: model.inAppId, in: window, using: viewController) } diff --git a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/ModalPresentationStrategy.swift b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/ModalPresentationStrategy.swift index c92fa2be..eb3a38c4 100644 --- a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/ModalPresentationStrategy.swift +++ b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/ModalPresentationStrategy.swift @@ -10,7 +10,7 @@ import UIKit import MindboxLogger final class ModalPresentationStrategy: PresentationStrategyProtocol { - var inappWindow: UIWindow? + var window: UIWindow? func getWindow() -> UIWindow? { return makeInAppMessageWindow() @@ -28,6 +28,10 @@ final class ModalPresentationStrategy: PresentationStrategyProtocol { Logger.common(message: "In-app modal presentation dismissed", level: .debug, category: .inAppMessages) } + func setupWindowFrame(model: MindboxFormVariant, imageSize: CGSize) { + // Not need to setup. + } + private func makeInAppMessageWindow() -> UIWindow? { let window: UIWindow? if #available(iOS 13.0, *) { @@ -35,8 +39,8 @@ final class ModalPresentationStrategy: PresentationStrategyProtocol { } else { window = UIWindow(frame: UIScreen.main.bounds) } - self.inappWindow = window - window?.windowLevel = UIWindow.Level.normal + self.window = window + window?.windowLevel = .normal + 3 window?.isHidden = false return window } diff --git a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/PresentationStrategyProtocol.swift b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/PresentationStrategyProtocol.swift index b7621250..806b8424 100644 --- a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/PresentationStrategyProtocol.swift +++ b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/PresentationStrategyProtocol.swift @@ -9,7 +9,10 @@ import UIKit protocol PresentationStrategyProtocol { + var window: UIWindow? { get set } + func getWindow() -> UIWindow? func present(id: String, in window: UIWindow, using viewController: UIViewController) func dismiss(viewController: UIViewController) + func setupWindowFrame(model: MindboxFormVariant, imageSize: CGSize) } diff --git a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift index 2360e009..97388213 100644 --- a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift +++ b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift @@ -10,19 +10,112 @@ import UIKit import MindboxLogger final class SnackbarPresentationStrategy: PresentationStrategyProtocol { - func getWindow() -> UIWindow? { - return UIApplication.shared.windows.first(where: { $0.isKeyWindow }) + + enum Constants { + static let oneThirdScreenHeight: CGFloat = UIScreen.main.bounds.height / 3.0 } + var window: UIWindow? + + func getWindow() -> UIWindow? { + let window: UIWindow + let screenBounds = UIScreen.main.bounds + let windowFrame = CGRect(x: 0, y: 0, width: screenBounds.width, height: screenBounds.height) + Logger.common(message: "SnackbarPresentationStrategy getWindow started.") + if #available(iOS 13, *) { + if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene { + window = UIWindow(windowScene: windowScene) + } else { + window = UIWindow(frame: UIScreen.main.bounds) + } + } else { + window = UIWindow(frame: UIScreen.main.bounds) + } + + window.frame = windowFrame + window.backgroundColor = .clear + window.windowLevel = .normal + 3 + let viewController = UIViewController() + window.rootViewController = viewController + viewController.view.frame = windowFrame + window.isHidden = false + self.window = window + return window + } + func present(id: String, in window: UIWindow, using viewController: UIViewController) { - window.rootViewController?.addChild(viewController) - window.rootViewController?.view.addSubview(viewController.view) - Logger.common(message: "In-app with id \(id) presented", level: .info, category: .inAppMessages) + if var topController = window.rootViewController { + while let presentedViewController = topController.presentedViewController { + topController = presentedViewController + } + + viewController.view.frame = topController.view.frame + topController.addChild(viewController) + topController.view.addSubview(viewController.view) + + viewController.view.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + viewController.view.topAnchor.constraint(equalTo: topController.view.topAnchor), + viewController.view.bottomAnchor.constraint(equalTo: topController.view.bottomAnchor), + viewController.view.leadingAnchor.constraint(equalTo: topController.view.leadingAnchor), + viewController.view.trailingAnchor.constraint(equalTo: topController.view.trailingAnchor) + ]) + + viewController.didMove(toParent: topController) + Logger.common(message: "In-app snackbar with id \(id) presented", level: .info, category: .inAppMessages) + } else { + Logger.common(message: "Unable to get top controller. Abort.", level: .error, category: .inAppMessages) + } } func dismiss(viewController: UIViewController) { viewController.view.removeFromSuperview() viewController.removeFromParent() - Logger.common(message: "InApp presentation dismissed", level: .debug, category: .inAppMessages) + Logger.common(message: "In-app snackbar presentation dismissed", level: .debug, category: .inAppMessages) + } + + func setupWindowFrame(model: MindboxFormVariant, imageSize: CGSize) { + switch model { + case .snackbar(let snackbarFormVariant): + if let gravity = snackbarFormVariant.content.position.gravity?.vertical { + let leftOffset = snackbarFormVariant.content.position.margin.left + let rightOffset = snackbarFormVariant.content.position.margin.right + let width = UIScreen.main.bounds.width - leftOffset - rightOffset + let heightMultiplier = width / imageSize.width + let imageHeight = imageSize.height * heightMultiplier + let finalHeight = (imageHeight < Constants.oneThirdScreenHeight) ? imageHeight : Constants.oneThirdScreenHeight + let safeAreaInset = getSafeAreaInset(gravity: gravity) + let y = getYPosition(gravity: gravity, finalHeight: finalHeight, safeAreaInset: safeAreaInset) + self.window?.frame = CGRect(x: leftOffset, y: y, width: width, height: finalHeight) + } + default: + break + } + } +} + +private extension SnackbarPresentationStrategy { + func getSafeAreaInset(gravity: GravityVerticalType) -> CGFloat { + var safeAreaInset: CGFloat = 0 + if #available(iOS 11, *) { + if gravity == .bottom { + safeAreaInset = window?.safeAreaInsets.bottom ?? 0 + } else if gravity == .top { + safeAreaInset = window?.safeAreaInsets.top ?? 0 + } + } + + return safeAreaInset + } + + func getYPosition(gravity: GravityVerticalType, finalHeight: CGFloat, safeAreaInset: CGFloat) -> CGFloat { + var y = UIScreen.main.bounds.height - finalHeight + if gravity == .bottom { + y = UIScreen.main.bounds.height - finalHeight - safeAreaInset + } else if gravity == .top { + y = safeAreaInset + } + + return y } } diff --git a/Mindbox/InAppMessages/Presentation/Views/CommonViews/ElementFactory/CloseButtonFactory/CloseButtonElementFactory.swift b/Mindbox/InAppMessages/Presentation/Views/CommonViews/ElementFactory/CloseButtonFactory/CloseButtonElementFactory.swift index 34023bf3..0f4eed2a 100644 --- a/Mindbox/InAppMessages/Presentation/Views/CommonViews/ElementFactory/CloseButtonFactory/CloseButtonElementFactory.swift +++ b/Mindbox/InAppMessages/Presentation/Views/CommonViews/ElementFactory/CloseButtonFactory/CloseButtonElementFactory.swift @@ -9,9 +9,9 @@ import UIKit class CloseButtonElementFactory: ElementFactory { - func create(from element: ContentElement, in view: UIView, with controller: GestureHandler) -> UIView? { + func create(from element: ContentElement, with controller: GestureHandler) -> UIView? { if case .closeButton(let closeButtonElement) = element { - let color = closeButtonElement.color?.isHexValid() ?? false ? closeButtonElement.color : nil + let color = closeButtonElement.color.isHexValid() ? closeButtonElement.color : nil let closeButton = CrossView(lineColorHex: color, lineWidth: closeButtonElement.lineWidth) closeButton.isUserInteractionEnabled = true let closeRecognizer = UILongPressGestureRecognizer(target: controller, action: #selector(controller.onCloseButton)) @@ -26,9 +26,9 @@ class CloseButtonElementFactory: ElementFactory { func setupConstraints(for view: UIView, from element: ContentElement, in parentView: UIView) { if case .closeButton(let closeButtonElement) = element { - let size = closeButtonElement.size?.element ?? ContentElementSize(kind: .dp, width: 24, height: 24) - let top = closeButtonElement.position?.margin?.element?.top ?? 0.02 - let right = closeButtonElement.position?.margin?.element?.right ?? 0.02 + let size = closeButtonElement.size + let top = closeButtonElement.position.margin.top + let right = closeButtonElement.position.margin.right let horizontalOffset = (parentView.frame.width - CGFloat(size.width)) * right let verticalOffset = (parentView.frame.height - CGFloat(size.height)) * top diff --git a/Mindbox/InAppMessages/Presentation/Views/CommonViews/ElementFactory/ElementFactory.swift b/Mindbox/InAppMessages/Presentation/Views/CommonViews/ElementFactory/ElementFactory.swift index aee49a5c..ea46e436 100644 --- a/Mindbox/InAppMessages/Presentation/Views/CommonViews/ElementFactory/ElementFactory.swift +++ b/Mindbox/InAppMessages/Presentation/Views/CommonViews/ElementFactory/ElementFactory.swift @@ -9,6 +9,6 @@ import UIKit protocol ElementFactory { - func create(from element: ContentElement, in view: UIView, with controller: GestureHandler) -> UIView? + func create(from element: ContentElement, with controller: GestureHandler) -> UIView? func setupConstraints(for view: UIView, from element: ContentElement, in parentView: UIView) } diff --git a/Mindbox/InAppMessages/Presentation/Views/CommonViews/InAppImageOnlyView.swift b/Mindbox/InAppMessages/Presentation/Views/CommonViews/InAppImageOnlyView.swift index f8e008af..d991fa97 100644 --- a/Mindbox/InAppMessages/Presentation/Views/CommonViews/InAppImageOnlyView.swift +++ b/Mindbox/InAppMessages/Presentation/Views/CommonViews/InAppImageOnlyView.swift @@ -6,6 +6,7 @@ // import UIKit +import MindboxLogger final class InAppImageOnlyView: UIView { var onClose: (() -> Void)? @@ -29,9 +30,12 @@ final class InAppImageOnlyView: UIView { func customInit() { guard let image = image else { + Logger.common(message: "[Error]: \(#function) at line \(#line) of \(#file)", level: .error) return } + Logger.common(message: "InAppImageOnlyView custom init started.") + imageView.contentMode = .scaleAspectFill imageView.image = image diff --git a/Mindbox/InAppMessages/Presentation/Views/CommonViews/LayersFactory/ImageLayer/ImageLayerFactory.swift b/Mindbox/InAppMessages/Presentation/Views/CommonViews/LayersFactory/ImageLayer/ImageLayerFactory.swift index e185019a..eda52d9d 100644 --- a/Mindbox/InAppMessages/Presentation/Views/CommonViews/LayersFactory/ImageLayer/ImageLayerFactory.swift +++ b/Mindbox/InAppMessages/Presentation/Views/CommonViews/LayersFactory/ImageLayer/ImageLayerFactory.swift @@ -7,6 +7,7 @@ // import UIKit +import MindboxLogger class ImageLayerFactory: LayerFactory { func create(from image: UIImage, layer: ContentBackgroundLayer, in view: UIView, with controller: GestureHandler) -> UIView? { @@ -14,10 +15,11 @@ class ImageLayerFactory: LayerFactory { let inAppView = InAppImageOnlyView(image: image, action: imageContentBackgroundLayer.action) let imageTapGestureRecognizer = UITapGestureRecognizer(target: controller, action: #selector(controller.imageTapped(_:))) inAppView.addGestureRecognizer(imageTapGestureRecognizer) - + Logger.common(message: "ImageLayerFactory return uiView.") return inAppView } - + + Logger.common(message: "ImageLayerFactory return nil.") return nil } @@ -39,5 +41,6 @@ class ImageLayerFactory: LayerFactory { view.leadingAnchor.constraint(equalTo: parentView.leadingAnchor), view.trailingAnchor.constraint(equalTo: parentView.trailingAnchor) ]) + Logger.common(message: "ImageLayerFactory setupConstraintsSnackbar finished.") } } diff --git a/Mindbox/InAppMessages/Presentation/Views/ModalView/ModalViewController.swift b/Mindbox/InAppMessages/Presentation/Views/ModalView/ModalViewController.swift index dbd3b145..969b3a78 100644 --- a/Mindbox/InAppMessages/Presentation/Views/ModalView/ModalViewController.swift +++ b/Mindbox/InAppMessages/Presentation/Views/ModalView/ModalViewController.swift @@ -34,14 +34,14 @@ final class ModalViewController: UIViewController, InappViewControllerProtocol, init( model: ModalFormVariant, id: String, - image: UIImage, + imagesDict: [String: UIImage], onPresented: @escaping () -> Void, onTapAction: @escaping (ContentBackgroundLayerAction?) -> Void, onClose: @escaping () -> Void ) { self.model = model self.id = id - self.image = image + self.imagesDict = imagesDict self.onPresented = onPresented self.onClose = onClose self.onTapAction = onTapAction @@ -54,7 +54,7 @@ final class ModalViewController: UIViewController, InappViewControllerProtocol, private let model: ModalFormVariant private let id: String - private let image: UIImage + private let imagesDict: [String: UIImage] private let onPresented: () -> Void private let onClose: () -> Void private let onTapAction: (ContentBackgroundLayerAction?) -> Void @@ -71,6 +71,10 @@ final class ModalViewController: UIViewController, InappViewControllerProtocol, override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() + elements.forEach({ + $0.removeFromSuperview() + }) + setupElements() } @@ -108,31 +112,35 @@ final class ModalViewController: UIViewController, InappViewControllerProtocol, } private func setupLayers() { - let layers = model.content.background.layers.elements + let layers = model.content.background.layers for layer in layers { if let factory = layersFactories[layer.layerType] { - let layerView = factory.create(from: self.image, layer: layer, in: view, with: self) - if let layerView = layerView { - self.layers.append(layerView) - view.addSubview(layerView) - factory.setupConstraints(for: layerView, in: view) + if case .image(let imageContentBackgroundLayer) = layer { + if case .url(let urlModel) = imageContentBackgroundLayer.source, let image = imagesDict[urlModel.value] { + let layerView = factory.create(from: image, layer: layer, in: view, with: self) + if let layerView = layerView { + self.layers.append(layerView) + view.addSubview(layerView) + factory.setupConstraints(for: layerView, in: view) + } + } } } } } private func setupElements() { - guard let elements = model.content.elements?.elements, + guard let elements = model.content.elements, let inappView = layers.first(where: { $0 is InAppImageOnlyView }) else { return } - + for element in elements { if let factory = elementFactories[element.elementType] { - let elementView = factory.create(from: element, in: inappView, with: self) + let elementView = factory.create(from: element, with: self) if let elementView = elementView { self.elements.append(elementView) - inappView.addSubview(elementView) + view.addSubview(elementView) factory.setupConstraints(for: elementView, from: element, in: inappView) } } diff --git a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarView.swift b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarView.swift index 486f7b32..93bd7aab 100644 --- a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarView.swift +++ b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarView.swift @@ -6,6 +6,7 @@ // import UIKit +import MindboxLogger class SnackbarView: UIView { @@ -39,7 +40,7 @@ class SnackbarView: UIView { self.onClose = onClose self.animationTime = animationTime super.init(frame: .zero) - + Logger.common(message: "SnackbarView inited.") setupPanGesture() } @@ -72,6 +73,7 @@ class SnackbarView: UIView { if ((swipeDirection == .up && translation.y < 0) || (swipeDirection == .down && translation.y > 0)) && abs(translation.y) > threshold { animateHide(completion: onClose, animated: true) + } else { UIView.animate(withDuration: animationTime) { self.transform = .identity @@ -113,6 +115,7 @@ class SnackbarView: UIView { } required init?(coder: NSCoder) { + Logger.common(message: "SnackbarView init(coder:) has not been implemented.") fatalError("init(coder:) has not been implemented") } } diff --git a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift index 52cb1eac..a3c45664 100644 --- a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift +++ b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift @@ -10,8 +10,7 @@ import UIKit import MindboxLogger class SnackbarViewController: UIViewController, InappViewControllerProtocol { - - var snackbarView: SnackbarView? + var edgeConstraint: NSLayoutConstraint? let model: SnackbarFormVariant @@ -27,17 +26,17 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { ] var leftOffset: CGFloat { - return model.content.position?.margin?.element?.left ?? 0 + return model.content.position.margin.left } var rightOffset: CGFloat { - return model.content.position?.margin?.element?.right ?? 0 + return model.content.position.margin.right } - private let id: String - public let image: UIImage + private let imagesDict: [String: UIImage] + let snackbarView: SnackbarView + private let firstImageValue: String private let onPresented: () -> Void - private let onClose: () -> Void private let onTapAction: (ContentBackgroundLayerAction?) -> Void private var hasSetupLayers = false @@ -51,34 +50,33 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { init( model: SnackbarFormVariant, - id: String, - image: UIImage, + imagesDict: [String: UIImage], + snackbarView: SnackbarView, + firstImageValue: String, onPresented: @escaping () -> Void, - onTapAction: @escaping (ContentBackgroundLayerAction?) -> Void, - onClose: @escaping () -> Void + onTapAction: @escaping (ContentBackgroundLayerAction?) -> Void ) { self.model = model - self.id = id - self.image = image + self.imagesDict = imagesDict + self.snackbarView = snackbarView + self.firstImageValue = firstImageValue self.onPresented = onPresented - self.onClose = onClose self.onTapAction = onTapAction super.init(nibName: nil, bundle: nil) + Logger.common(message: "SnackbarViewController inited.") } required init?(coder: NSCoder) { + Logger.common(message: "SnackbarViewController init(coder:) has not been implemented.") fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { super.viewDidLoad() + view.addSubview(snackbarView) view.isUserInteractionEnabled = true - snackbarView = SnackbarView(onClose: onClose) - if let snackbarView = snackbarView { - snackbarView.translatesAutoresizingMaskIntoConstraints = false - snackbarView.isUserInteractionEnabled = true - view.addSubview(snackbarView) - } + snackbarView.translatesAutoresizingMaskIntoConstraints = false + snackbarView.isUserInteractionEnabled = true } override func viewDidLayoutSubviews() { @@ -88,11 +86,11 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { setupConstraints() setupLayers() - if snackbarView?.bounds.size != .zero { + if snackbarView.bounds.size != .zero { setupElements() hasSetupElements = true } - } else if !hasSetupElements && snackbarView?.bounds.size != .zero { + } else if !hasSetupElements && snackbarView.bounds.size != .zero { UIView.performWithoutAnimation { setupElements() hasSetupElements = true @@ -108,32 +106,28 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { } private func setupLayers() { - let layers = model.content.background.layers.elements - guard let snackbarView = snackbarView else { - return - } - + let layers = model.content.background.layers + for layer in layers { if let factory = layersFactories[layer.layerType] { - let layerView = factory.create(from: self.image, layer: layer, in: snackbarView, with: self) - if let layerView = layerView { - self.layers.append(layerView) - snackbarView.addSubview(layerView) - factory.setupConstraintsSnackbar(for: layerView, in: snackbarView) + if case .image(let imageContentBackgroundLayer) = layer { + if case .url(let urlModel) = imageContentBackgroundLayer.source, let image = imagesDict[urlModel.value] { + let layerView = factory.create(from: image, layer: layer, in: view, with: self) + if let layerView = layerView { + self.layers.append(layerView) + snackbarView.addSubview(layerView) + factory.setupConstraintsSnackbar(for: layerView, in: snackbarView) + } + } } } } } - private func setupElements() { - guard let elements = model.content.elements?.elements, - let snackbarView = snackbarView else { - return - } - - for element in elements { + private func setupElements() { + for element in model.content.elements { if let factory = elementFactories[element.elementType] { - let elementView = factory.create(from: element, in: snackbarView, with: self) + let elementView = factory.create(from: element, with: self) if let elementView = elementView { self.elements.append(elementView) snackbarView.addSubview(elementView) @@ -157,15 +151,17 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { } func setupConstraints() { - let width = view.layer.frame.width - leftOffset - rightOffset + guard let image = imagesDict[firstImageValue] else { + Logger.common(message: "[Error]: \(#function) at line \(#line) of \(#file)", level: .error) + return + } + + let width = view.layer.frame.width let heightMultiplier = width / image.size.width let imageHeight = image.size.height * heightMultiplier let finalHeight = (imageHeight < Constants.oneThirdScreenHeight) ? imageHeight : Constants.oneThirdScreenHeight setViewFrame(with: finalHeight) - guard let snackbarView = snackbarView else { - return - } snackbarView.swipeDirection = swipeDirection snackbarView.translatesAutoresizingMaskIntoConstraints = false @@ -179,17 +175,15 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { } func setupLayoutConstraints(with height: CGFloat) { - guard let snackbarView = snackbarView else { - return - } - if #available(iOS 11.0, *) { + Logger.common(message: "SnackbarViewController setupLayoutConstraints iOS 11+.") NSLayoutConstraint.activate([ snackbarView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), snackbarView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor), snackbarView.heightAnchor.constraint(equalToConstant: height), ]) } else { + Logger.common(message: "SnackbarViewController setupLayoutConstraints iOS 10.") NSLayoutConstraint.activate([ snackbarView.leadingAnchor.constraint(equalTo: view.leadingAnchor), snackbarView.trailingAnchor.constraint(equalTo: view.trailingAnchor), @@ -206,6 +200,7 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { extension SnackbarViewController: GestureHandler { @objc func imageTapped(_ sender: UITapGestureRecognizer) { guard let imageView = sender.view as? InAppImageOnlyView else { + Logger.common(message: "[Error]: \(#function) at line \(#line) of \(#file)", level: .error) return } @@ -215,13 +210,14 @@ extension SnackbarViewController: GestureHandler { @objc func onCloseButton(_ gesture: UILongPressGestureRecognizer) { guard let crossView = gesture.view else { + Logger.common(message: "[Error]: \(#function) at line \(#line) of \(#file)", level: .error) return } let location = gesture.location(in: crossView) let isInsideCrossView = crossView.bounds.contains(location) if gesture.state == .ended && isInsideCrossView { - snackbarView?.hide() + snackbarView.hide() } } } @@ -246,9 +242,9 @@ class TopSnackbarViewController: SnackbarViewController { override func setupEdgeConstraint(with height: CGFloat) { if #available(iOS 11.0, *) { - edgeConstraint = snackbarView?.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: -height) + edgeConstraint = snackbarView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: -height) } else { - edgeConstraint = snackbarView?.topAnchor.constraint(equalTo: view.topAnchor, constant: -height) + edgeConstraint = snackbarView.topAnchor.constraint(equalTo: view.topAnchor, constant: -height) } edgeConstraint?.isActive = true @@ -273,13 +269,16 @@ class BottomSnackbarViewController: SnackbarViewController { self.view.frame = CGRect(x: leftOffset, y: screenHeight - finalHeight, width: UIScreen.main.bounds.width - leftOffset - rightOffset, height: finalHeight) + Logger.common(message: "SnackbarViewController setViewFrame function finished.") } override func setupEdgeConstraint(with height: CGFloat) { if #available(iOS 11.0, *) { - edgeConstraint = snackbarView?.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: height) + Logger.common(message: "SnackbarViewController setupEdgeConstraint iOS 11+.") + edgeConstraint = snackbarView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: height) } else { - edgeConstraint = snackbarView?.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: height) + Logger.common(message: "SnackbarViewController setupEdgeConstraint iOS 10.") + edgeConstraint = snackbarView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: height) } edgeConstraint?.isActive = true diff --git a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/ModalViewFactory.swift b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/ModalViewFactory.swift index e1225317..07a6a449 100644 --- a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/ModalViewFactory.swift +++ b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/ModalViewFactory.swift @@ -13,14 +13,15 @@ class ModalViewFactory: ViewFactoryProtocol { func create(model: MindboxFormVariant, id: String, - image: UIImage, + imagesDict: [String: UIImage], + firstImageValue: String, onPresented: @escaping () -> Void, onTapAction: @escaping (ContentBackgroundLayerAction?) -> Void, onClose: @escaping () -> Void) -> UIViewController? { if case .modal(let modalFormVariant) = model { let viewController = ModalViewController(model: modalFormVariant, id: id, - image: image, + imagesDict: imagesDict, onPresented: onPresented, onTapAction: onTapAction, onClose: onClose) diff --git a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift index 3f46ebd1..b009d91f 100644 --- a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift +++ b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift @@ -8,29 +8,34 @@ import Foundation import UIKit +import MindboxLogger class SnackbarViewFactory: ViewFactoryProtocol { weak var viewController: UIViewController? - func create(model: MindboxFormVariant, id: String, image: UIImage, onPresented: @escaping () -> Void, onTapAction: @escaping (ContentBackgroundLayerAction?) -> Void, onClose: @escaping () -> Void) -> UIViewController? { + func create(model: MindboxFormVariant, id: String, imagesDict: [String: UIImage], firstImageValue: String, onPresented: @escaping () -> Void, onTapAction: @escaping (ContentBackgroundLayerAction?) -> Void, onClose: @escaping () -> Void) -> UIViewController? { if case .snackbar(let snackbarFormVariant) = model { - if let gravity = snackbarFormVariant.content.position?.gravity?.element?.vertical { + if let gravity = snackbarFormVariant.content.position.gravity?.vertical { var snackbarViewController: UIViewController? + let snackbarView = SnackbarView(onClose: onClose) switch gravity { case .top: - snackbarViewController = TopSnackbarViewController(model: snackbarFormVariant, id: id, image: image, onPresented: onPresented, onTapAction: onTapAction, onClose: onClose) + snackbarViewController = TopSnackbarViewController(model: snackbarFormVariant, imagesDict: imagesDict, snackbarView: snackbarView, firstImageValue: firstImageValue, onPresented: onPresented, onTapAction: onTapAction) case .bottom: - snackbarViewController = BottomSnackbarViewController(model: snackbarFormVariant, id: id, image: image, onPresented: onPresented, onTapAction: onTapAction, onClose: onClose) + snackbarViewController = BottomSnackbarViewController(model: snackbarFormVariant, imagesDict: imagesDict, snackbarView: snackbarView, firstImageValue: firstImageValue, onPresented: onPresented, onTapAction: onTapAction) default: + Logger.common(message: "SnackbarViewFactory controller is nil.") return nil } self.viewController = snackbarViewController + return viewController } } - + + Logger.common(message: "SnackbarViewFactory create returns nil.") return nil } } diff --git a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/ViewFactoryProtocol.swift b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/ViewFactoryProtocol.swift index af67960e..edbbb402 100644 --- a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/ViewFactoryProtocol.swift +++ b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/ViewFactoryProtocol.swift @@ -12,7 +12,8 @@ import Foundation protocol ViewFactoryProtocol { func create(model: MindboxFormVariant, id: String, - image: UIImage, + imagesDict: [String: UIImage], + firstImageValue: String, onPresented: @escaping () -> Void, onTapAction: @escaping (ContentBackgroundLayerAction?) -> Void, onClose: @escaping () -> Void) -> UIViewController? diff --git a/Mindbox/Info.plist b/Mindbox/Info.plist index ea2f1d8a..c6cff490 100644 --- a/Mindbox/Info.plist +++ b/Mindbox/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 4781 + 4897 diff --git a/MindboxNotifications.podspec b/MindboxNotifications.podspec index 7565b752..79169eea 100644 --- a/MindboxNotifications.podspec +++ b/MindboxNotifications.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = "MindboxNotifications" - spec.version = "2.8.0-rc" + spec.version = "2.8.0" spec.summary = "SDK for integration notifications with Mindbox" spec.description = "This library allows you to integrate notifications and transfer them to Mindbox Marketing Cloud" spec.homepage = "https://github.com/mindbox-cloud/ios-sdk" diff --git a/MindboxTests/DI/TestDependencyProvider.swift b/MindboxTests/DI/TestDependencyProvider.swift index 53723f51..dac96f5e 100644 --- a/MindboxTests/DI/TestDependencyProvider.swift +++ b/MindboxTests/DI/TestDependencyProvider.swift @@ -11,6 +11,7 @@ import XCTest @testable import Mindbox final class TestDependencyProvider: DependencyContainer { + var inAppTargetingChecker: InAppTargetingChecker let inAppMessagesManager: InAppCoreManagerProtocol let utilitiesFetcher: UtilitiesFetcher @@ -30,6 +31,7 @@ final class TestDependencyProvider: DependencyContainer { var imageDownloadService: ImageDownloadServiceProtocol var abTestDeviceMixer: ABTestDeviceMixer var urlExtractorService: VariantImageUrlExtractorService + var inappFilterService: InappFilterProtocol init() throws { sessionTemporaryStorage = SessionTemporaryStorage() @@ -66,6 +68,18 @@ final class TestDependencyProvider: DependencyContainer { imageDownloadService = MockImageDownloadService() abTestDeviceMixer = ABTestDeviceMixer() urlExtractorService = VariantImageUrlExtractorService() + let actionFilter = LayerActionFilterService() + 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, colorFilter: colorFilter) + let contentPositionFilterService = ContentPositionFilterService() + let variantsFilterService = VariantFilterService(layersFilter: layersFilterService, + elementsFilter: elementsFilterService, + contentPositionFilter: contentPositionFilterService) + inappFilterService = InappsFilterService(variantsFilter: variantsFilterService) } } diff --git a/MindboxTests/InApp/Tests/ABTesting/ABTests.swift b/MindboxTests/InApp/Tests/ABTesting/ABTests.swift index ebfe99e2..20ad9811 100644 --- a/MindboxTests/InApp/Tests/ABTesting/ABTests.swift +++ b/MindboxTests/InApp/Tests/ABTesting/ABTests.swift @@ -1,842 +1,843 @@ +//// +//// ABTests.swift +//// MindboxTests +//// +//// Created by vailence on 19.06.2023. +//// Copyright © 2023 Mindbox. All rights reserved. +//// // -// ABTests.swift -// MindboxTests -// -// Created by vailence on 19.06.2023. -// Copyright © 2023 Mindbox. All rights reserved. -// - -import Foundation -import XCTest -@testable import Mindbox - -class ABTests: XCTestCase { - - var container = try! TestDependencyProvider() - - var sessionTemporaryStorage: SessionTemporaryStorage { - container.sessionTemporaryStorage - } - - var persistenceStorage: PersistenceStorage { - container.persistenceStorage - } - - var networkFetcher: NetworkFetcher { - container.instanceFactory.makeNetworkFetcher() - } - - var sdkVersionValidator: SDKVersionValidator! - - private var mapper: InAppConfigutationMapper! - private let configStub = InAppConfigStub() - private let targetingChecker: InAppTargetingCheckerProtocol = InAppTargetingChecker() - private var shownInAppsIds: Set! - - override func setUp() { - super.setUp() - sdkVersionValidator = SDKVersionValidator(sdkVersionNumeric: 6) - mapper = InAppConfigutationMapper(geoService: container.geoService, - segmentationService: container.segmentationSevice, - customerSegmentsAPI: .live, - targetingChecker: targetingChecker, - sessionTemporaryStorage: sessionTemporaryStorage, - persistenceStorage: persistenceStorage, - sdkVersionValidator: sdkVersionValidator, - imageDownloadService: container.imageDownloadService, - urlExtractorService: container.urlExtractorService, - abTestDeviceMixer: container.abTestDeviceMixer) - shownInAppsIds = Set(persistenceStorage.shownInAppsIds ?? []) - } - - func test_no_abtests() throws { - let response = try getConfig(name: "ConfigWithAB_1") - let abTests: [ABTest]? = nil - let inapps = mapper.filterInappsByABTests(abTests, responseInapps: response.inapps?.elements) - XCTAssertEqual(inapps.count, 3) - let expectedIds = [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - - runInAppTestForUUID("BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", - abTests: abTests, - responseInapps: response.inapps?.elements, - expectedCount: 3, expectedIds: expectedIds) - } - - func test_compare_inapps_with_cg() throws { - let response = try getConfig(name: "ConfigWithAB_1") - let abTests: [ABTest]? = [ - ABTest( - id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", - sdkVersion: SdkVersion(min: 6, max: nil), - salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", - variants: [ - ABTest.ABTestVariant( - id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", - modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 50), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [] - ) - ] - ), - ABTest.ABTestVariant( - id: "211f1c16-fa72-4456-bf87-af448eb84a32", - modulus: ABTest.ABTestVariant.Modulus(lower: 50, upper: 100), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .all, - inapps: nil - ) - ] - ) - ] - ) - ] - - runInAppTestForUUID("4078E211-7C3F-C607-D35C-DC6B591EF355", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: 0, expectedIds: []) // 25 - - let expectedIds = [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - - runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: 3, expectedIds: expectedIds) // 75 - } - - func test_compare_cg_and_concrete_inapps() throws { - let response = try getConfig(name: "ConfigWithAB_2") - let abTests: [ABTest]? = [ - ABTest( - id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", - sdkVersion: SdkVersion(min: 6, max: nil), - salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", - variants: [ - ABTest.ABTestVariant( - id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", - modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 50), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [] - ) - ] - ), - ABTest.ABTestVariant( - id: "211f1c16-fa72-4456-bf87-af448eb84a32", - modulus: ABTest.ABTestVariant.Modulus(lower: 50, upper: 100), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - ) - ] - ) - ] - ) - ] - - // Test case for UUID "4078E211-7C3F-C607-D35C-DC6B591EF355" with expected inapp count of 2 - let expectedIds1 = [ - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", - "d1b312bd-aa5c-414c-a0d8-8126376a2a9b" - ] - runInAppTestForUUID("4078E211-7C3F-C607-D35C-DC6B591EF355", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: 2, expectedIds: expectedIds1) - - // Test case for UUID "4D27710A-3F3A-FF6E-7764-375B1E06E05D" with expected inapp count of 4 - let expectedIds2 = [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", - "b33ca779-3c99-481f-ad46-91282b0caf04", - "d1b312bd-aa5c-414c-a0d8-8126376a2a9b" - ] - runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: 4, expectedIds: expectedIds2) - } - - func test_compare_cg_and_concrete_inapps_and_all_inapps() throws { - let response = try getConfig(name: "ConfigWithAB_1") - let abTests: [ABTest]? = [ - ABTest( - id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", - sdkVersion: SdkVersion(min: 6, max: nil), - salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", - variants: [ - ABTest.ABTestVariant( - id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", - modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 30), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [] - ) - ] - ), - ABTest.ABTestVariant( - id: "211f1c16-fa72-4456-bf87-af448eb84a32", - modulus: ABTest.ABTestVariant.Modulus(lower: 30, upper: 65), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - ) - ] - ), - ABTest.ABTestVariant( - id: "36e69720-8e73-447c-b172-7b17e2d73525", - modulus: ABTest.ABTestVariant.Modulus(lower: 65, upper: 100), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .all, - inapps: nil - ) - ] - ) - ] - ) - ] - - // Test case for UUID "4078E211-7C3F-C607-D35C-DC6B591EF355" with expected inapp count of 0 - runInAppTestForUUID("4078E211-7C3F-C607-D35C-DC6B591EF355", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: 0, expectedIds: []) - - // Test case for UUID "0809B0F8-8F21-18E8-2EF8-EC2D98938A84" with expected inapp count of 2 - let expectedIds1 = [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - runInAppTestForUUID("0809B0F8-8F21-18E8-2EF8-EC2D98938A84", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: 2, expectedIds: expectedIds1) - - // Test case for UUID "4D27710A-3F3A-FF6E-7764-375B1E06E05D" with expected inapp count of 3 - let expectedIds2 = [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: 3, expectedIds: expectedIds2) - } - - func test_compare_2branch_and_concrete_inapps_and_cg() throws { - let response = try getConfig(name: "ConfigWithAB_2") - let abTests: [ABTest]? = [ - ABTest( - id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", - sdkVersion: SdkVersion(min: 6, max: nil), - salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", - variants: [ - ABTest.ABTestVariant( - id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", - modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 27), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [] - ) - ] - ), - ABTest.ABTestVariant( - id: "211f1c16-fa72-4456-bf87-af448eb84a32", - modulus: ABTest.ABTestVariant.Modulus(lower: 27, upper: 65), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d" - ] - ) - ] - ), - ABTest.ABTestVariant( - id: "36e69720-8e73-447c-b172-7b17e2d73525", - modulus: ABTest.ABTestVariant.Modulus(lower: 65, upper: 100), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - ) - ] - ) - ] - ) - ] - - // Test case for UUID "4078E211-7C3F-C607-D35C-DC6B591EF355" with expected inapp count of 2 - let expectedIds1 = [ - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", - "d1b312bd-aa5c-414c-a0d8-8126376a2a9b" - ] - runInAppTestForUUID("4078E211-7C3F-C607-D35C-DC6B591EF355", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) - - // Test case for UUID "0809B0F8-8F21-18E8-2EF8-EC2D98938A84" with expected inapp count of 3 - let expectedIds2 = [ - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", - "d1b312bd-aa5c-414c-a0d8-8126376a2a9b", - "655f5ffa-de86-4224-a0bf-229fe208ed0d" - ] - runInAppTestForUUID("0809B0F8-8F21-18E8-2EF8-EC2D98938A84", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) - - // Test case for UUID "4D27710A-3F3A-FF6E-7764-375B1E06E05D" with expected inapp count of 3 - let expectedIds3 = [ - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", - "d1b312bd-aa5c-414c-a0d8-8126376a2a9b", - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds3.count, expectedIds: expectedIds3) - } - - func test_compare_2branch_and_concrete_inapps() throws { - let response = try getConfig(name: "ConfigWithAB_1") - let abTests: [ABTest]? = [ - ABTest( - id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", - sdkVersion: SdkVersion(min: 6, max: nil), - salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", - variants: [ - ABTest.ABTestVariant( - id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", - modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 99), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - ) - ] - ), - ABTest.ABTestVariant( - id: "211f1c16-fa72-4456-bf87-af448eb84a32", - modulus: ABTest.ABTestVariant.Modulus(lower: 99, upper: 100), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83" - ] - ) - ] - ) - ] - ) - ] - - // Test case for UUID "4078E211-7C3F-C607-D35C-DC6B591EF355" with expected inapp count of 2 - let expectedIds1 = [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - runInAppTestForUUID("4078E211-7C3F-C607-D35C-DC6B591EF355", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) - - // Test case for UUID "0809B0F8-8F21-18E8-2EF8-EC2D98938A84" with expected inapp count of 3 - let expectedIds2 = [ - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83" - ] - runInAppTestForUUID("C9F84B44-01B9-A3C6-E85B-7FF816D3BA68", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) - } - - func test_aab_show_inapps_in_cg_branch() throws { - let response = try getConfig(name: "ConfigWithAB_1") - let abTests: [ABTest]? = [ - ABTest( - id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", - sdkVersion: SdkVersion(min: 6, max: nil), - salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", - variants: [ - ABTest.ABTestVariant( - id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", - modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 33), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [] - ) - ] - ), - ABTest.ABTestVariant( - id: "211f1c16-fa72-4456-bf87-af448eb84a32", - modulus: ABTest.ABTestVariant.Modulus(lower: 33, upper: 66), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [] - ) - ] - ), - ABTest.ABTestVariant( - id: "36e69720-8e73-447c-b172-7b17e2d73525", - modulus: ABTest.ABTestVariant.Modulus(lower: 66, upper: 100), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - ) - ] - ) - ] - ) - ] - - // Test case for UUID "4862ADF1-1392-9362-42A2-FF5A65629F50" with expected inapp count of 2 - let expectedIds1 = [ - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83" - ] - runInAppTestForUUID("4862ADF1-1392-9362-42A2-FF5A65629F50", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 25 - - // Test case for UUID "0809B0F8-8F21-18E8-2EF8-EC2D98938A84" with expected inapp count of 3 - runInAppTestForUUID("0809B0F8-8F21-18E8-2EF8-EC2D98938A84", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 45 - - let expectedIds2 = [ - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - // Test case for UUID "4D27710A-3F3A-FF6E-7764-375B1E06E05D" with expected inapp count of 3 - runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) // 75 - } - - func test_aab_not_show_inapps_in_cg_branch() throws { - let response = try getConfig(name: "ConfigWithAB_1") - let abTests: [ABTest]? = [ - ABTest( - id: "c0e2682c-3d0f-4291-9308-9e48a16eb3c8", - sdkVersion: SdkVersion(min: 6, max: nil), - salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", - variants: [ - ABTest.ABTestVariant( - id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", - modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 33), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [] - ) - ] - ), - ABTest.ABTestVariant( - id: "211f1c16-fa72-4456-bf87-af448eb84a32", - modulus: ABTest.ABTestVariant.Modulus(lower: 33, upper: 66), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [] - ) - ] - ), - ABTest.ABTestVariant( - id: "36e69720-8e73-447c-b172-7b17e2d73525", - modulus: ABTest.ABTestVariant.Modulus(lower: 66, upper: 100), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "b33ca779-3c99-481f-ad46-91282b0caf04", - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83" - ] - ) - ] - ) - ] - ) - ] - - // Test case for UUID "4862ADF1-1392-9362-42A2-FF5A65629F50" with expected inapp count of 2 - let expectedIds1 = [String]() - runInAppTestForUUID("4862ADF1-1392-9362-42A2-FF5A65629F50", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 25 - - // Test case for UUID "0809B0F8-8F21-18E8-2EF8-EC2D98938A84" with expected inapp count of 3 - runInAppTestForUUID("0809B0F8-8F21-18E8-2EF8-EC2D98938A84", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 45 - - let expectedIds2 = [ - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - // Test case for UUID "4D27710A-3F3A-FF6E-7764-375B1E06E05D" with expected inapp count of 3 - runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) // 75 - } - - func test_ab_limit_value_check() throws { - let response = try getConfig(name: "ConfigWithAB_1") - let abTests: [ABTest]? = [ - ABTest( - id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", - sdkVersion: SdkVersion(min: 6, max: nil), - salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", - variants: [ - ABTest.ABTestVariant( - id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", - modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 33), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [] - ) - ] - ), - ABTest.ABTestVariant( - id: "211f1c16-fa72-4456-bf87-af448eb84a32", - modulus: ABTest.ABTestVariant.Modulus(lower: 33, upper: 99), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d" - ] - ) - ] - ), - ABTest.ABTestVariant( - id: "36e69720-8e73-447c-b172-7b17e2d73525", - modulus: ABTest.ABTestVariant.Modulus(lower: 99, upper: 100), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - ) - ] - ) - ] - ) - ] - - // Test case for UUID "F3AB8877-CB55-CE3D-1AB3-230D2EA8A220" with expected inapp count of 2 - let expectedIds1 = ["6f93e2ef-0615-4e63-9c80-24bcb9e83b83"] - runInAppTestForUUID("F3AB8877-CB55-CE3D-1AB3-230D2EA8A220", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 0 - - let expectedIds2 = [ - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - ] - // Test case for UUID "3A9F107E-9FBE-8D83-EFE9-5F093001CD54" with expected inapp count of 3 - runInAppTestForUUID("3A9F107E-9FBE-8D83-EFE9-5F093001CD54", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) // 33 - - let expectedIds3 = [ - "b33ca779-3c99-481f-ad46-91282b0caf04", - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", - ] - // Test case for UUID "59B675D6-9AF1-1805-2BB3-90C3CF11E5E0" with expected inapp count of 3 - runInAppTestForUUID("59B675D6-9AF1-1805-2BB3-90C3CF11E5E0", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds3.count, expectedIds: expectedIds3) // 99 - } - - func test_compare_5_ab_tests_in_one_branch() throws { - let response = try getConfig(name: "ConfigWithAB_2") - let abTests: [ABTest]? = [ - ABTest( - id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", - sdkVersion: SdkVersion(min: 6, max: nil), - salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", - variants: [ - ABTest.ABTestVariant( - id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", - modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 10), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d" - ] - ) - ] - ), - ABTest.ABTestVariant( - id: "211f1c16-fa72-4456-bf87-af448eb84a32", - modulus: ABTest.ABTestVariant.Modulus(lower: 10, upper: 20), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83" - ] - ) - ] - ), - ABTest.ABTestVariant( - id: "36e69720-8e73-447c-b172-7b17e2d73525", - modulus: ABTest.ABTestVariant.Modulus(lower: 20, upper: 30), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - ) - ] - ), - ABTest.ABTestVariant( - id: "479b3748-747e-476f-afcd-7a9ce3f0ec71", - modulus: ABTest.ABTestVariant.Modulus(lower: 30, upper: 70), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "d1b312bd-aa5c-414c-a0d8-8126376a2a9b" - ] - ) - ] - ), - ABTest.ABTestVariant( - id: "5fb3e501-11c2-418d-b774-2ee26d31f556", - modulus: ABTest.ABTestVariant.Modulus(lower: 70, upper: 100), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .all, - inapps: nil - ) - ] - ) - ] - ) - ] - - // Test case for UUID "7544976E-FEA4-6A48-EB5D-85A6EEB4D306" with expected inapp count of 21 - let expectedIds1 = ["655f5ffa-de86-4224-a0bf-229fe208ed0d"] - runInAppTestForUUID("7544976E-FEA4-6A48-EB5D-85A6EEB4D306", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 5 - - let expectedIds2 = ["6f93e2ef-0615-4e63-9c80-24bcb9e83b83"] - // Test case for UUID "618F8CA3-282D-5B18-7186-F2CF361ABD32" with expected inapp count of 1 - runInAppTestForUUID("618F8CA3-282D-5B18-7186-F2CF361ABD32", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) // 15 - - let expectedIds3 = ["b33ca779-3c99-481f-ad46-91282b0caf04"] - runInAppTestForUUID("DC0F2330-785B-5D80-CD34-F2F520AD618F", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds3.count, expectedIds: expectedIds3) // 25 - - let expectedIds4 = ["d1b312bd-aa5c-414c-a0d8-8126376a2a9b"] - runInAppTestForUUID("0809B0F8-8F21-18E8-2EF8-EC2D98938A84", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds4.count, expectedIds: expectedIds4) // 45 - - let expectedIds5 = [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", - "b33ca779-3c99-481f-ad46-91282b0caf04", - "d1b312bd-aa5c-414c-a0d8-8126376a2a9b"] - runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds5.count, expectedIds: expectedIds5) // 75 - } - - func test_2_different_ab_tests_one() throws { - let response = try getConfig(name: "ConfigWithAB_1") - let abtests: [ABTest]? = [ - ABTest( - id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", - sdkVersion: SdkVersion(min: 6, max: nil), - salt: "c0e2682c-3d0f-4291-9308-9e48a16eb3c8", - variants: [ - ABTest.ABTestVariant( - id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", - modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 25), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [] - ) - ] - ), - ABTest.ABTestVariant( - id: "211f1c16-fa72-4456-bf87-af448eb84a32", - modulus: ABTest.ABTestVariant.Modulus(lower: 25, upper: 100), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .all, - inapps: nil - ) - ] - ) - ] - ), - ABTest( - id: "1ec6be6b-421f-464b-9ee4-348a5292a5fd", - sdkVersion: SdkVersion(min: 6, max: nil), - salt: "b142ff09-68c4-41f9-985d-d220edfad4f", - variants: [ - ABTest.ABTestVariant( - id: "36e69720-8e73-447c-b172-7b17e2d73525", - modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 75), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [] - ) - ] - ), - ABTest.ABTestVariant( - id: "479b3748-747e-476f-afcd-7a9ce3f0ec71", - modulus: ABTest.ABTestVariant.Modulus(lower: 75, upper: 100), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83" - ] - ) - ] - ) - ] - ) - ] - - let expectedIds1 = [String]() - runInAppTestForUUID("9d7f8e6c-3a2b-4d9a-b1c0-1e1e3a4b5c6d", abTests: abtests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 23 and 29 - - runInAppTestForUUID("284c10f7-4f4c-4a1b-92e0-2318f2ae13c9", abTests: abtests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 1 and 91 - - let expectedIds2 = ["b33ca779-3c99-481f-ad46-91282b0caf04"] - runInAppTestForUUID("677a789d-9a98-4f03-9cb2-af2563fc1d07", abTests: abtests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) // 88 and 5 - - let expectedIds3 = ["b33ca779-3c99-481f-ad46-91282b0caf04", - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83"] - runInAppTestForUUID("d35df6c2-9e20-4f7e-9e20-51894e2c4810", abTests: abtests, responseInapps: response.inapps?.elements, expectedCount: expectedIds3.count, expectedIds: expectedIds3) // 61 and 94 - } - - func test_2_different_ab_tests_two() throws { -// XCTAssertTrue(false) - } - - func test_concrete_inapps_and_all() throws { - let response = try getConfig(name: "ConfigWithAB_1") - let abtests: [ABTest]? = [ - ABTest( - id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", - sdkVersion: SdkVersion(min: 6, max: nil), - salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", - variants: [ - ABTest.ABTestVariant( - id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", - modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 35), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - ) - ] - ), - ABTest.ABTestVariant( - id: "211f1c16-fa72-4456-bf87-af448eb84a32", - modulus: ABTest.ABTestVariant.Modulus(lower: 35, upper: 100), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .all, - inapps: nil - ) - ] - ) - ] - ) - ] - - // Test case for UUID "F3AB8877-CB55-CE3D-1AB3-230D2EA8A220" with expected inapp count of 2 - let expectedIds1 = [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - - runInAppTestForUUID("4078E211-7C3F-C607-D35C-DC6B591EF355", abTests: abtests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 25 - - let expectedIds2 = [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "b33ca779-3c99-481f-ad46-91282b0caf04", - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83" - ] - - runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abtests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) // 75 - } - - func test_section_ab_broken_return_nil() throws { - let response = try getConfig(name: "ConfigWithABBrokenRange") // Отсутствует диапазон 33-66 - XCTAssertNil(response.abtests) - - let response2 = try getConfig(name: "ConfigWithABNoSalt") // Отсутствует соль - XCTAssertNil(response2.abtests) - - let response3 = try getConfig(name: "ConfigWithABUnexpectedValue") // Неожиданное ключ-значение - XCTAssertNil(response3.abtests) - - let response4 = try getConfig(name: "ConfigWithABCrossRange") // Неожиданное ключ-значение - XCTAssertNil(response4.abtests) - - let response5 = try getConfig(name: "ConfigWithABNoUpper") // Отсутствует ключ upper в одном из вариантов - XCTAssertNil(response5.abtests) - - let response6 = try getConfig(name: "ConfigWithABLowerBiggerThanUpper") // Lower больше, чем Upper - XCTAssertNil(response6.abtests) - } - - func test_sdkversion_lower_than_ab_tests_version() throws { - let response = try getConfig(name: "ConfigWithABNormal") - XCTAssertNil(response.abtests) - } - - func test_ab_test_type_not_inapps_return_nil() throws { - let response = try getConfig(name: "ConfigWithABTypeNotInapps") - XCTAssertNil(response.abtests) - } -} - -private extension ABTests { - private func getConfig(name: String) throws -> ConfigResponse { - let bundle = Bundle(for: ABTests.self) - let fileURL = bundle.url(forResource: name, withExtension: "json")! - let data = try Data(contentsOf: fileURL) - return try JSONDecoder().decode(ConfigResponse.self, from: data) - } - - private func runInAppTestForUUID(_ uuid: String, abTests: [ABTest]?, responseInapps: [InApp]?, expectedCount: Int, expectedIds: [String]) { - persistenceStorage.deviceUUID = uuid - let inapps = mapper.filterInappsByABTests(abTests, responseInapps: responseInapps) - XCTAssertEqual(inapps.count, expectedCount) - for inapp in inapps { - XCTAssertTrue(expectedIds.contains { $0 == inapp.id }) - } - } -} +//import Foundation +//import XCTest +//@testable import Mindbox +// +//class ABTests: XCTestCase { +// +// var container = try! TestDependencyProvider() +// +// var sessionTemporaryStorage: SessionTemporaryStorage { +// container.sessionTemporaryStorage +// } +// +// var persistenceStorage: PersistenceStorage { +// container.persistenceStorage +// } +// +// var networkFetcher: NetworkFetcher { +// container.instanceFactory.makeNetworkFetcher() +// } +// +// var sdkVersionValidator: SDKVersionValidator! +// +// private var mapper: InAppConfigutationMapper! +// private let configStub = InAppConfigStub() +// private let targetingChecker: InAppTargetingCheckerProtocol = InAppTargetingChecker() +// private var shownInAppsIds: Set! +// +// override func setUp() { +// super.setUp() +// sdkVersionValidator = SDKVersionValidator(sdkVersionNumeric: 6) +// mapper = InAppConfigutationMapper(inappFilterService: container.inappFilterService, +// geoService: container.geoService, +// segmentationService: container.segmentationSevice, +// customerSegmentsAPI: .live, +// targetingChecker: targetingChecker, +// sessionTemporaryStorage: sessionTemporaryStorage, +// persistenceStorage: persistenceStorage, +// sdkVersionValidator: sdkVersionValidator, +// imageDownloadService: container.imageDownloadService, +// urlExtractorService: container.urlExtractorService, +// abTestDeviceMixer: container.abTestDeviceMixer) +// shownInAppsIds = Set(persistenceStorage.shownInAppsIds ?? []) +// } +// +// func test_no_abtests() throws { +// let response = try getConfig(name: "ConfigWithAB_1") +// let abTests: [ABTest]? = nil +// let inapps = mapper.filterInappsByABTests(abTests, responseInapps: response.inapps?.elements) +// XCTAssertEqual(inapps.count, 3) +// let expectedIds = [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// +// runInAppTestForUUID("BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", +// abTests: abTests, +// responseInapps: response.inapps?.elements, +// expectedCount: 3, expectedIds: expectedIds) +// } +// +// func test_compare_inapps_with_cg() throws { +// let response = try getConfig(name: "ConfigWithAB_1") +// let abTests: [ABTest]? = [ +// ABTest( +// id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", +// sdkVersion: SdkVersion(min: 6, max: nil), +// salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", +// variants: [ +// ABTest.ABTestVariant( +// id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", +// modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 50), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "211f1c16-fa72-4456-bf87-af448eb84a32", +// modulus: ABTest.ABTestVariant.Modulus(lower: 50, upper: 100), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .all, +// inapps: nil +// ) +// ] +// ) +// ] +// ) +// ] +// +// runInAppTestForUUID("4078E211-7C3F-C607-D35C-DC6B591EF355", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: 0, expectedIds: []) // 25 +// +// let expectedIds = [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// +// runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: 3, expectedIds: expectedIds) // 75 +// } +// +// func test_compare_cg_and_concrete_inapps() throws { +// let response = try getConfig(name: "ConfigWithAB_2") +// let abTests: [ABTest]? = [ +// ABTest( +// id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", +// sdkVersion: SdkVersion(min: 6, max: nil), +// salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", +// variants: [ +// ABTest.ABTestVariant( +// id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", +// modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 50), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "211f1c16-fa72-4456-bf87-af448eb84a32", +// modulus: ABTest.ABTestVariant.Modulus(lower: 50, upper: 100), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// ) +// ] +// ) +// ] +// ) +// ] +// +// // Test case for UUID "4078E211-7C3F-C607-D35C-DC6B591EF355" with expected inapp count of 2 +// let expectedIds1 = [ +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", +// "d1b312bd-aa5c-414c-a0d8-8126376a2a9b" +// ] +// runInAppTestForUUID("4078E211-7C3F-C607-D35C-DC6B591EF355", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: 2, expectedIds: expectedIds1) +// +// // Test case for UUID "4D27710A-3F3A-FF6E-7764-375B1E06E05D" with expected inapp count of 4 +// let expectedIds2 = [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", +// "b33ca779-3c99-481f-ad46-91282b0caf04", +// "d1b312bd-aa5c-414c-a0d8-8126376a2a9b" +// ] +// runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: 4, expectedIds: expectedIds2) +// } +// +// func test_compare_cg_and_concrete_inapps_and_all_inapps() throws { +// let response = try getConfig(name: "ConfigWithAB_1") +// let abTests: [ABTest]? = [ +// ABTest( +// id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", +// sdkVersion: SdkVersion(min: 6, max: nil), +// salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", +// variants: [ +// ABTest.ABTestVariant( +// id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", +// modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 30), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "211f1c16-fa72-4456-bf87-af448eb84a32", +// modulus: ABTest.ABTestVariant.Modulus(lower: 30, upper: 65), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "36e69720-8e73-447c-b172-7b17e2d73525", +// modulus: ABTest.ABTestVariant.Modulus(lower: 65, upper: 100), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .all, +// inapps: nil +// ) +// ] +// ) +// ] +// ) +// ] +// +// // Test case for UUID "4078E211-7C3F-C607-D35C-DC6B591EF355" with expected inapp count of 0 +// runInAppTestForUUID("4078E211-7C3F-C607-D35C-DC6B591EF355", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: 0, expectedIds: []) +// +// // Test case for UUID "0809B0F8-8F21-18E8-2EF8-EC2D98938A84" with expected inapp count of 2 +// let expectedIds1 = [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// runInAppTestForUUID("0809B0F8-8F21-18E8-2EF8-EC2D98938A84", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: 2, expectedIds: expectedIds1) +// +// // Test case for UUID "4D27710A-3F3A-FF6E-7764-375B1E06E05D" with expected inapp count of 3 +// let expectedIds2 = [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: 3, expectedIds: expectedIds2) +// } +// +// func test_compare_2branch_and_concrete_inapps_and_cg() throws { +// let response = try getConfig(name: "ConfigWithAB_2") +// let abTests: [ABTest]? = [ +// ABTest( +// id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", +// sdkVersion: SdkVersion(min: 6, max: nil), +// salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", +// variants: [ +// ABTest.ABTestVariant( +// id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", +// modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 27), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "211f1c16-fa72-4456-bf87-af448eb84a32", +// modulus: ABTest.ABTestVariant.Modulus(lower: 27, upper: 65), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d" +// ] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "36e69720-8e73-447c-b172-7b17e2d73525", +// modulus: ABTest.ABTestVariant.Modulus(lower: 65, upper: 100), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// ) +// ] +// ) +// ] +// ) +// ] +// +// // Test case for UUID "4078E211-7C3F-C607-D35C-DC6B591EF355" with expected inapp count of 2 +// let expectedIds1 = [ +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", +// "d1b312bd-aa5c-414c-a0d8-8126376a2a9b" +// ] +// runInAppTestForUUID("4078E211-7C3F-C607-D35C-DC6B591EF355", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) +// +// // Test case for UUID "0809B0F8-8F21-18E8-2EF8-EC2D98938A84" with expected inapp count of 3 +// let expectedIds2 = [ +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", +// "d1b312bd-aa5c-414c-a0d8-8126376a2a9b", +// "655f5ffa-de86-4224-a0bf-229fe208ed0d" +// ] +// runInAppTestForUUID("0809B0F8-8F21-18E8-2EF8-EC2D98938A84", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) +// +// // Test case for UUID "4D27710A-3F3A-FF6E-7764-375B1E06E05D" with expected inapp count of 3 +// let expectedIds3 = [ +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", +// "d1b312bd-aa5c-414c-a0d8-8126376a2a9b", +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds3.count, expectedIds: expectedIds3) +// } +// +// func test_compare_2branch_and_concrete_inapps() throws { +// let response = try getConfig(name: "ConfigWithAB_1") +// let abTests: [ABTest]? = [ +// ABTest( +// id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", +// sdkVersion: SdkVersion(min: 6, max: nil), +// salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", +// variants: [ +// ABTest.ABTestVariant( +// id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", +// modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 99), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "211f1c16-fa72-4456-bf87-af448eb84a32", +// modulus: ABTest.ABTestVariant.Modulus(lower: 99, upper: 100), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83" +// ] +// ) +// ] +// ) +// ] +// ) +// ] +// +// // Test case for UUID "4078E211-7C3F-C607-D35C-DC6B591EF355" with expected inapp count of 2 +// let expectedIds1 = [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// runInAppTestForUUID("4078E211-7C3F-C607-D35C-DC6B591EF355", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) +// +// // Test case for UUID "0809B0F8-8F21-18E8-2EF8-EC2D98938A84" with expected inapp count of 3 +// let expectedIds2 = [ +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83" +// ] +// runInAppTestForUUID("C9F84B44-01B9-A3C6-E85B-7FF816D3BA68", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) +// } +// +// func test_aab_show_inapps_in_cg_branch() throws { +// let response = try getConfig(name: "ConfigWithAB_1") +// let abTests: [ABTest]? = [ +// ABTest( +// id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", +// sdkVersion: SdkVersion(min: 6, max: nil), +// salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", +// variants: [ +// ABTest.ABTestVariant( +// id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", +// modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 33), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "211f1c16-fa72-4456-bf87-af448eb84a32", +// modulus: ABTest.ABTestVariant.Modulus(lower: 33, upper: 66), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "36e69720-8e73-447c-b172-7b17e2d73525", +// modulus: ABTest.ABTestVariant.Modulus(lower: 66, upper: 100), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// ) +// ] +// ) +// ] +// ) +// ] +// +// // Test case for UUID "4862ADF1-1392-9362-42A2-FF5A65629F50" with expected inapp count of 2 +// let expectedIds1 = [ +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83" +// ] +// runInAppTestForUUID("4862ADF1-1392-9362-42A2-FF5A65629F50", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 25 +// +// // Test case for UUID "0809B0F8-8F21-18E8-2EF8-EC2D98938A84" with expected inapp count of 3 +// runInAppTestForUUID("0809B0F8-8F21-18E8-2EF8-EC2D98938A84", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 45 +// +// let expectedIds2 = [ +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// // Test case for UUID "4D27710A-3F3A-FF6E-7764-375B1E06E05D" with expected inapp count of 3 +// runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) // 75 +// } +// +// func test_aab_not_show_inapps_in_cg_branch() throws { +// let response = try getConfig(name: "ConfigWithAB_1") +// let abTests: [ABTest]? = [ +// ABTest( +// id: "c0e2682c-3d0f-4291-9308-9e48a16eb3c8", +// sdkVersion: SdkVersion(min: 6, max: nil), +// salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", +// variants: [ +// ABTest.ABTestVariant( +// id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", +// modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 33), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "211f1c16-fa72-4456-bf87-af448eb84a32", +// modulus: ABTest.ABTestVariant.Modulus(lower: 33, upper: 66), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "36e69720-8e73-447c-b172-7b17e2d73525", +// modulus: ABTest.ABTestVariant.Modulus(lower: 66, upper: 100), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "b33ca779-3c99-481f-ad46-91282b0caf04", +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83" +// ] +// ) +// ] +// ) +// ] +// ) +// ] +// +// // Test case for UUID "4862ADF1-1392-9362-42A2-FF5A65629F50" with expected inapp count of 2 +// let expectedIds1 = [String]() +// runInAppTestForUUID("4862ADF1-1392-9362-42A2-FF5A65629F50", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 25 +// +// // Test case for UUID "0809B0F8-8F21-18E8-2EF8-EC2D98938A84" with expected inapp count of 3 +// runInAppTestForUUID("0809B0F8-8F21-18E8-2EF8-EC2D98938A84", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 45 +// +// let expectedIds2 = [ +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// // Test case for UUID "4D27710A-3F3A-FF6E-7764-375B1E06E05D" with expected inapp count of 3 +// runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) // 75 +// } +// +// func test_ab_limit_value_check() throws { +// let response = try getConfig(name: "ConfigWithAB_1") +// let abTests: [ABTest]? = [ +// ABTest( +// id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", +// sdkVersion: SdkVersion(min: 6, max: nil), +// salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", +// variants: [ +// ABTest.ABTestVariant( +// id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", +// modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 33), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "211f1c16-fa72-4456-bf87-af448eb84a32", +// modulus: ABTest.ABTestVariant.Modulus(lower: 33, upper: 99), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d" +// ] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "36e69720-8e73-447c-b172-7b17e2d73525", +// modulus: ABTest.ABTestVariant.Modulus(lower: 99, upper: 100), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// ) +// ] +// ) +// ] +// ) +// ] +// +// // Test case for UUID "F3AB8877-CB55-CE3D-1AB3-230D2EA8A220" with expected inapp count of 2 +// let expectedIds1 = ["6f93e2ef-0615-4e63-9c80-24bcb9e83b83"] +// runInAppTestForUUID("F3AB8877-CB55-CE3D-1AB3-230D2EA8A220", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 0 +// +// let expectedIds2 = [ +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// ] +// // Test case for UUID "3A9F107E-9FBE-8D83-EFE9-5F093001CD54" with expected inapp count of 3 +// runInAppTestForUUID("3A9F107E-9FBE-8D83-EFE9-5F093001CD54", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) // 33 +// +// let expectedIds3 = [ +// "b33ca779-3c99-481f-ad46-91282b0caf04", +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", +// ] +// // Test case for UUID "59B675D6-9AF1-1805-2BB3-90C3CF11E5E0" with expected inapp count of 3 +// runInAppTestForUUID("59B675D6-9AF1-1805-2BB3-90C3CF11E5E0", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds3.count, expectedIds: expectedIds3) // 99 +// } +// +// func test_compare_5_ab_tests_in_one_branch() throws { +// let response = try getConfig(name: "ConfigWithAB_2") +// let abTests: [ABTest]? = [ +// ABTest( +// id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", +// sdkVersion: SdkVersion(min: 6, max: nil), +// salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", +// variants: [ +// ABTest.ABTestVariant( +// id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", +// modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 10), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d" +// ] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "211f1c16-fa72-4456-bf87-af448eb84a32", +// modulus: ABTest.ABTestVariant.Modulus(lower: 10, upper: 20), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83" +// ] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "36e69720-8e73-447c-b172-7b17e2d73525", +// modulus: ABTest.ABTestVariant.Modulus(lower: 20, upper: 30), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "479b3748-747e-476f-afcd-7a9ce3f0ec71", +// modulus: ABTest.ABTestVariant.Modulus(lower: 30, upper: 70), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "d1b312bd-aa5c-414c-a0d8-8126376a2a9b" +// ] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "5fb3e501-11c2-418d-b774-2ee26d31f556", +// modulus: ABTest.ABTestVariant.Modulus(lower: 70, upper: 100), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .all, +// inapps: nil +// ) +// ] +// ) +// ] +// ) +// ] +// +// // Test case for UUID "7544976E-FEA4-6A48-EB5D-85A6EEB4D306" with expected inapp count of 21 +// let expectedIds1 = ["655f5ffa-de86-4224-a0bf-229fe208ed0d"] +// runInAppTestForUUID("7544976E-FEA4-6A48-EB5D-85A6EEB4D306", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 5 +// +// let expectedIds2 = ["6f93e2ef-0615-4e63-9c80-24bcb9e83b83"] +// // Test case for UUID "618F8CA3-282D-5B18-7186-F2CF361ABD32" with expected inapp count of 1 +// runInAppTestForUUID("618F8CA3-282D-5B18-7186-F2CF361ABD32", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) // 15 +// +// let expectedIds3 = ["b33ca779-3c99-481f-ad46-91282b0caf04"] +// runInAppTestForUUID("DC0F2330-785B-5D80-CD34-F2F520AD618F", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds3.count, expectedIds: expectedIds3) // 25 +// +// let expectedIds4 = ["d1b312bd-aa5c-414c-a0d8-8126376a2a9b"] +// runInAppTestForUUID("0809B0F8-8F21-18E8-2EF8-EC2D98938A84", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds4.count, expectedIds: expectedIds4) // 45 +// +// let expectedIds5 = [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", +// "b33ca779-3c99-481f-ad46-91282b0caf04", +// "d1b312bd-aa5c-414c-a0d8-8126376a2a9b"] +// runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds5.count, expectedIds: expectedIds5) // 75 +// } +// +// func test_2_different_ab_tests_one() throws { +// let response = try getConfig(name: "ConfigWithAB_1") +// let abtests: [ABTest]? = [ +// ABTest( +// id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", +// sdkVersion: SdkVersion(min: 6, max: nil), +// salt: "c0e2682c-3d0f-4291-9308-9e48a16eb3c8", +// variants: [ +// ABTest.ABTestVariant( +// id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", +// modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 25), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "211f1c16-fa72-4456-bf87-af448eb84a32", +// modulus: ABTest.ABTestVariant.Modulus(lower: 25, upper: 100), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .all, +// inapps: nil +// ) +// ] +// ) +// ] +// ), +// ABTest( +// id: "1ec6be6b-421f-464b-9ee4-348a5292a5fd", +// sdkVersion: SdkVersion(min: 6, max: nil), +// salt: "b142ff09-68c4-41f9-985d-d220edfad4f", +// variants: [ +// ABTest.ABTestVariant( +// id: "36e69720-8e73-447c-b172-7b17e2d73525", +// modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 75), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "479b3748-747e-476f-afcd-7a9ce3f0ec71", +// modulus: ABTest.ABTestVariant.Modulus(lower: 75, upper: 100), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83" +// ] +// ) +// ] +// ) +// ] +// ) +// ] +// +// let expectedIds1 = [String]() +// runInAppTestForUUID("9d7f8e6c-3a2b-4d9a-b1c0-1e1e3a4b5c6d", abTests: abtests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 23 and 29 +// +// runInAppTestForUUID("284c10f7-4f4c-4a1b-92e0-2318f2ae13c9", abTests: abtests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 1 and 91 +// +// let expectedIds2 = ["b33ca779-3c99-481f-ad46-91282b0caf04"] +// runInAppTestForUUID("677a789d-9a98-4f03-9cb2-af2563fc1d07", abTests: abtests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) // 88 and 5 +// +// let expectedIds3 = ["b33ca779-3c99-481f-ad46-91282b0caf04", +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83"] +// runInAppTestForUUID("d35df6c2-9e20-4f7e-9e20-51894e2c4810", abTests: abtests, responseInapps: response.inapps?.elements, expectedCount: expectedIds3.count, expectedIds: expectedIds3) // 61 and 94 +// } +// +// func test_2_different_ab_tests_two() throws { +//// XCTAssertTrue(false) +// } +// +// func test_concrete_inapps_and_all() throws { +// let response = try getConfig(name: "ConfigWithAB_1") +// let abtests: [ABTest]? = [ +// ABTest( +// id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", +// sdkVersion: SdkVersion(min: 6, max: nil), +// salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", +// variants: [ +// ABTest.ABTestVariant( +// id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", +// modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 35), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "211f1c16-fa72-4456-bf87-af448eb84a32", +// modulus: ABTest.ABTestVariant.Modulus(lower: 35, upper: 100), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .all, +// inapps: nil +// ) +// ] +// ) +// ] +// ) +// ] +// +// // Test case for UUID "F3AB8877-CB55-CE3D-1AB3-230D2EA8A220" with expected inapp count of 2 +// let expectedIds1 = [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// +// runInAppTestForUUID("4078E211-7C3F-C607-D35C-DC6B591EF355", abTests: abtests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 25 +// +// let expectedIds2 = [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "b33ca779-3c99-481f-ad46-91282b0caf04", +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83" +// ] +// +// runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abtests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) // 75 +// } +// +// func test_section_ab_broken_return_nil() throws { +// let response = try getConfig(name: "ConfigWithABBrokenRange") // Отсутствует диапазон 33-66 +// XCTAssertNil(response.abtests) +// +// let response2 = try getConfig(name: "ConfigWithABNoSalt") // Отсутствует соль +// XCTAssertNil(response2.abtests) +// +// let response3 = try getConfig(name: "ConfigWithABUnexpectedValue") // Неожиданное ключ-значение +// XCTAssertNil(response3.abtests) +// +// let response4 = try getConfig(name: "ConfigWithABCrossRange") // Неожиданное ключ-значение +// XCTAssertNil(response4.abtests) +// +// let response5 = try getConfig(name: "ConfigWithABNoUpper") // Отсутствует ключ upper в одном из вариантов +// XCTAssertNil(response5.abtests) +// +// let response6 = try getConfig(name: "ConfigWithABLowerBiggerThanUpper") // Lower больше, чем Upper +// XCTAssertNil(response6.abtests) +// } +// +// func test_sdkversion_lower_than_ab_tests_version() throws { +// let response = try getConfig(name: "ConfigWithABNormal") +// XCTAssertNil(response.abtests) +// } +// +// func test_ab_test_type_not_inapps_return_nil() throws { +// let response = try getConfig(name: "ConfigWithABTypeNotInapps") +// XCTAssertNil(response.abtests) +// } +//} +// +//private extension ABTests { +// private func getConfig(name: String) throws -> ConfigResponse { +// let bundle = Bundle(for: ABTests.self) +// let fileURL = bundle.url(forResource: name, withExtension: "json")! +// let data = try Data(contentsOf: fileURL) +// return try JSONDecoder().decode(ConfigResponse.self, from: data) +// } +// +// private func runInAppTestForUUID(_ uuid: String, abTests: [ABTest]?, responseInapps: [InApp]?, expectedCount: Int, expectedIds: [String]) { +// persistenceStorage.deviceUUID = uuid +// let inapps = mapper.filterInappsByABTests(abTests, responseInapps: responseInapps) +// XCTAssertEqual(inapps.count, expectedCount) +// for inapp in inapps { +// XCTAssertTrue(expectedIds.contains { $0 == inapp.id }) +// } +// } +//} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/InappFilterServiceTests.swift b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/InappFilterServiceTests.swift new file mode 100644 index 00000000..361d00cb --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/InappFilterServiceTests.swift @@ -0,0 +1,320 @@ +// +// InappFilterServiceTests.swift +// MindboxTests +// +// Created by vailence on 14.09.2023. +// Copyright © 2023 Mindbox. All rights reserved. +// + +import XCTest +@testable import Mindbox + +final class InappFilterServiceTests: XCTestCase { + + enum Constants { + static let defaultID = "5696ac18-70cb-496f-80c5-a47eb7573df7" + static let defaultColor = "#FFFFFF" + static let defaultLineWidth = 2 + static let defaultSize: Double = 24 + } + + var sut: InappFilterProtocol! + var container = try! TestDependencyProvider() + + override func setUp() { + super.setUp() + sut = container.inappFilterService + } + + override func tearDown() { + sut = nil + super.tearDown() + } + + func test_unknown_type_for_variants() throws { + let config = try getConfig(name: "unknownVariantType") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, Constants.defaultID) + } + + func test_missingBackgroundSection() throws { + let config = try getConfig(name: "missingBackgroundSection") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, Constants.defaultID) + } + + func test_emptyLayersSection() throws { + let config = try getConfig(name: "emptyLayersSection") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, Constants.defaultID) + } + + func test_unknownLayerType() throws { + let config = try getConfig(name: "unknownLayerType") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, Constants.defaultID) + } + + func test_knownImageUnknownPictureLayerType() throws { + let config = try getConfig(name: "knownImageUnknownPictureLayerType") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 2) + + if let variant = inapps.first?.form.variants.first { + switch variant { + + case .modal(let model): + XCTAssertEqual(model.content.background.layers.count, 1) + default: + break + } + } + } + + func test_unknownActionLayerType() throws { + let config = try getConfig(name: "unknownActionLayerType") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, Constants.defaultID) + } + + func test_redirectUrlValueNumberInsteadOfString() throws { + let config = try getConfig(name: "redirectUrlValueNumberInsteadOfString") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, Constants.defaultID) + } + + func test_missingIntentPayloadInActionLayer() throws { + let config = try getConfig(name: "missingIntentPayloadInActionLayer") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, Constants.defaultID) + } + + func test_missingSourceSection() throws { + let config = try getConfig(name: "missingSourceSection") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, Constants.defaultID) + } + + func test_emptyVariantsArray() throws { + let config = try getConfig(name: "emptyVariantsArray") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, Constants.defaultID) + } + + func test_unknownSourceType() throws { + let config = try getConfig(name: "unknownSourceType") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, Constants.defaultID) + } + + func test_missingValueInSourceLayer() throws { + let config = try getConfig(name: "missingValueInSourceLayer") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, Constants.defaultID) + } + + func test_missingImageLinkInSourceLayerValue() throws { + let config = try getConfig(name: "missingImageLinkInSourceLayerValue") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, Constants.defaultID) + } + + func test_missingElementsSection() throws { + let config = try getConfig(name: "missingElementsSection") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 2) + + if let variant = inapps.first?.form.variants.first { + switch variant { + + case .modal(let model): + XCTAssertEqual(model.content.elements?.count, 0) + default: + break + } + } + } + + func test_invalidCloseButtonColor() throws { + let config = try getConfig(name: "invalidCloseButtonColor") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 2) + + if let variant = inapps.first?.form.variants.first { + switch variant { + case .modal(let model): + guard let type = model.content.elements?.first else { + assertionFailure("type not exists. ") + return + } + switch type { + case .closeButton(let model): + XCTAssertEqual(model.color, Constants.defaultColor) + default: + break + } + default: + break + } + } + } + + func test_missingCloseButtonColorLineWidthSize() throws { + let config = try getConfig(name: "missingCloseButtonColorLineWidthSize") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 2) + + if let variant = inapps.first?.form.variants.first { + switch variant { + case .modal(let model): + guard let type = model.content.elements?.first else { + assertionFailure("type not exists.") + return + } + switch type { + case .closeButton(let model): + XCTAssertEqual(model.color, Constants.defaultColor) + XCTAssertEqual(model.size.height, Constants.defaultSize) + XCTAssertEqual(model.size.width, Constants.defaultSize) + XCTAssertEqual(model.lineWidth, Constants.defaultLineWidth) + default: + break + } + default: + break + } + } + } + + func test_twoCloseButtonsInApp() throws { + let config = try getConfig(name: "twoCloseButtonsInApp") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 2) + + if let variant = inapps.first?.form.variants.first { + switch variant { + case .modal(let model): + guard let elements = model.content.elements else { + assertionFailure("elements not exists.") + return + } + + var counter = 0 + elements.forEach { + counter += $0.elementType == .closeButton ? 1 : 0 + } + + XCTAssertEqual(counter, 2) + default: + break + } + } + } + + func test_closeButtonWithOpenButton() throws { + let config = try getConfig(name: "closeButtonWithOpenButton") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 2) + + if let variant = inapps.first?.form.variants.first { + switch variant { + case .modal(let model): + guard let elements = model.content.elements else { + assertionFailure("elements not exists.") + return + } + + XCTAssertEqual(elements.count, 1) + switch elements.first! { + case .closeButton: + XCTAssertTrue(true) + return + default: + break + } + default: + break + } + } + + assertionFailure() + } + + func test_unknownSizeKind() throws { + let config = try getConfig(name: "unknownSizeKind") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 2) + + if let variant = inapps.first?.form.variants.first { + switch variant { + case .modal(let model): + guard let elements = model.content.elements else { + assertionFailure("elements not exists.") + return + } + + XCTAssertEqual(elements.count, 1) + switch elements.first! { + case .closeButton(let model): + XCTAssertEqual(model.size.kind, .dp) + XCTAssertEqual(model.size.width, Constants.defaultSize) + XCTAssertEqual(model.size.height, Constants.defaultSize) + return + default: + break + } + default: + break + } + } + + assertionFailure() + } + + func test_missingMarginFieldInSection() throws { + let config = try getConfig(name: "missingMarginFieldInSection") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, Constants.defaultID) + } + + func test_negativeCloseButtonSizeValues() throws { + let config = try getConfig(name: "negativeCloseButtonSizeValues") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, Constants.defaultID) + } + + func test_closeButtonMarginAboveOne() throws { + let config = try getConfig(name: "closeButtonMarginAboveOne") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, Constants.defaultID) + } + + func test_closeButtonMarginBelowZero() throws { + let config = try getConfig(name: "closeButtonMarginBelowZero") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, Constants.defaultID) + } + + private func getConfig(name: String) throws -> ConfigResponse { + let bundle = Bundle(for: InappFilterServiceTests.self) + let fileURL = bundle.url(forResource: name, withExtension: "json")! + let data = try Data(contentsOf: fileURL) + return try JSONDecoder().decode(ConfigResponse.self, from: data) + } +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /closeButtonMarginAboveOne.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /closeButtonMarginAboveOne.json new file mode 100644 index 00000000..31b59903 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /closeButtonMarginAboveOne.json @@ -0,0 +1,206 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 1.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "pixel", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /closeButtonMarginBelowZero.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /closeButtonMarginBelowZero.json new file mode 100644 index 00000000..944cb679 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /closeButtonMarginBelowZero.json @@ -0,0 +1,206 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": -0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "pixel", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /closeButtonWithOpenButton.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /closeButtonWithOpenButton.json new file mode 100644 index 00000000..47325400 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /closeButtonWithOpenButton.json @@ -0,0 +1,225 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + }, + "source": { + "$type": "url", + "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + }, + { + "$type": "openButton", + "color": "#000000", + "lineWidth": 8, + "size": { + "kind": "dp", + "width": 12, + "height": 12 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", + "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + }, + "source": { + "$type": "url", + "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", + "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /emptyLayersSection.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /emptyLayersSection.json new file mode 100644 index 00000000..5719b9e3 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /emptyLayersSection.json @@ -0,0 +1,193 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /emptyVariantsArray.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /emptyVariantsArray.json new file mode 100644 index 00000000..b92479f7 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /emptyVariantsArray.json @@ -0,0 +1,160 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /invalidCloseButtonColor.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /invalidCloseButtonColor.json new file mode 100644 index 00000000..ef9d3b74 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /invalidCloseButtonColor.json @@ -0,0 +1,206 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#12345", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#0000FF", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /knownImageUnknownPictureLayerType.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /knownImageUnknownPictureLayerType.json new file mode 100644 index 00000000..b62e65ce --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /knownImageUnknownPictureLayerType.json @@ -0,0 +1,218 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + }, + { + "$type": "picture", + "action": { + "$type": "redirectUrl", + "intentPayload": "", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingBackgroundSection.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingBackgroundSection.json new file mode 100644 index 00000000..e2d00bf3 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingBackgroundSection.json @@ -0,0 +1,190 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingCloseButtonColorLineWidthSize.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingCloseButtonColorLineWidthSize.json new file mode 100644 index 00000000..74c00c49 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingCloseButtonColorLineWidthSize.json @@ -0,0 +1,199 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingElementsSection.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingElementsSection.json new file mode 100644 index 00000000..f203b0e1 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingElementsSection.json @@ -0,0 +1,164 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + } + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + } + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingImageLinkInSourceLayerValue.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingImageLinkInSourceLayerValue.json new file mode 100644 index 00000000..fe43e6b1 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingImageLinkInSourceLayerValue.json @@ -0,0 +1,206 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "1" + }, + "source": { + "$type": "url", + "value": "" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingIntentPayloadInActionLayer.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingIntentPayloadInActionLayer.json new file mode 100644 index 00000000..6d866c1f --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingIntentPayloadInActionLayer.json @@ -0,0 +1,330 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "openUrl", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + }, + { + "$type": "image", + "action": { + "$type": "openUrl", + "intentPayload": "modal payload_layer2", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0, + "bottom": 0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "1496ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "snackbar", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "snackbar payload_layer1", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + }, + { + "$type": "image", + "action": { + "$type": "openUrl", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "position": { + "gravity": { + "horizontal": "center", + "vertical": "bottom" + }, + "margin": { + "kind": "dp", + "top": 0.0, + "bottom": 0.0, + "left": 25.0, + "right": 25.0 + } + }, + "elements": [ + { + "$type": "closeButton", + "color": "#255F00", + "lineWidth": 3, + "size": { + "kind": "dp", + "width": 30, + "height": 30 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0, + "bottom": 0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingMarginFieldInSection.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingMarginFieldInSection.json new file mode 100644 index 00000000..12c41f7e --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingMarginFieldInSection.json @@ -0,0 +1,205 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "pixel", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingSourceSection.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingSourceSection.json new file mode 100644 index 00000000..031292aa --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingSourceSection.json @@ -0,0 +1,202 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingValueInSourceLayer.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingValueInSourceLayer.json new file mode 100644 index 00000000..85ae154c --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingValueInSourceLayer.json @@ -0,0 +1,205 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "1" + }, + "source": { + "$type": "url" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /negativeCloseButtonSizeValues.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /negativeCloseButtonSizeValues.json new file mode 100644 index 00000000..aa2b698f --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /negativeCloseButtonSizeValues.json @@ -0,0 +1,206 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": -32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "pixel", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /redirectUrlValueNumberInsteadOfString.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /redirectUrlValueNumberInsteadOfString.json new file mode 100644 index 00000000..cd8732c3 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /redirectUrlValueNumberInsteadOfString.json @@ -0,0 +1,332 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "openUrl", + "intentPayload": "modal payload_layer1", + "value": 12345 + }, + "source": { + "$type": "url", + "value": "1" + } + }, + { + "$type": "image", + "action": { + "$type": "openUrl", + "intentPayload": "modal payload_layer2", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0, + "bottom": 0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "1496ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "snackbar", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "snackbar payload_layer1", + "value": 67890 + }, + "source": { + "$type": "url", + "value": "1" + } + }, + { + "$type": "image", + "action": { + "$type": "openUrl", + "intentPayload": "snackbar payload_layer2", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "position": { + "gravity": { + "horizontal": "center", + "vertical": "bottom" + }, + "margin": { + "kind": "dp", + "top": 0.0, + "bottom": 0.0, + "left": 25.0, + "right": 25.0 + } + }, + "elements": [ + { + "$type": "closeButton", + "color": "#255F00", + "lineWidth": 3, + "size": { + "kind": "dp", + "width": 30, + "height": 30 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0, + "bottom": 0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /twoCloseButtonsInApp.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /twoCloseButtonsInApp.json new file mode 100644 index 00000000..f45591ed --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /twoCloseButtonsInApp.json @@ -0,0 +1,225 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 6, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + }, + { + "$type": "closeButton", + "color": "#FFFFFF", + "lineWidth": 2, + "size": { + "kind": "dp", + "width": 45, + "height": 45 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownActionLayerType.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownActionLayerType.json new file mode 100644 index 00000000..cd8732c3 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownActionLayerType.json @@ -0,0 +1,332 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "openUrl", + "intentPayload": "modal payload_layer1", + "value": 12345 + }, + "source": { + "$type": "url", + "value": "1" + } + }, + { + "$type": "image", + "action": { + "$type": "openUrl", + "intentPayload": "modal payload_layer2", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0, + "bottom": 0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "1496ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "snackbar", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "snackbar payload_layer1", + "value": 67890 + }, + "source": { + "$type": "url", + "value": "1" + } + }, + { + "$type": "image", + "action": { + "$type": "openUrl", + "intentPayload": "snackbar payload_layer2", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "position": { + "gravity": { + "horizontal": "center", + "vertical": "bottom" + }, + "margin": { + "kind": "dp", + "top": 0.0, + "bottom": 0.0, + "left": 25.0, + "right": 25.0 + } + }, + "elements": [ + { + "$type": "closeButton", + "color": "#255F00", + "lineWidth": 3, + "size": { + "kind": "dp", + "width": 30, + "height": 30 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0, + "bottom": 0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownLayerType.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownLayerType.json new file mode 100644 index 00000000..f4237c4f --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownLayerType.json @@ -0,0 +1,206 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "picture", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownSizeKind.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownSizeKind.json new file mode 100644 index 00000000..d75098be --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownSizeKind.json @@ -0,0 +1,206 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "pixel", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "pixel", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownSourceType.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownSourceType.json new file mode 100644 index 00000000..51eab6a9 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownSourceType.json @@ -0,0 +1,206 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "1" + }, + "source": { + "$type": "link", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownVariantType.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownVariantType.json new file mode 100644 index 00000000..af322c39 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownVariantType.json @@ -0,0 +1,206 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "window", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "1" + }, + "source": { + "$type": "url", + "value": "1" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "1", + "redirectUrl": "1", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/VariantImageUrlExtractorServiceTests.swift b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/VariantImageUrlExtractorServiceTests.swift new file mode 100644 index 00000000..7df9aba3 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/VariantImageUrlExtractorServiceTests.swift @@ -0,0 +1,213 @@ +// +// VariantImageUrlExtractorServiceTests.swift +// MindboxTests +// +// Created by vailence on 04.09.2023. +// Copyright © 2023 Mindbox. All rights reserved. +// + +import XCTest +@testable import Mindbox + +final class VariantImageUrlExtractorServiceTests: XCTestCase { + + var sut: VariantImageUrlExtractorServiceProtocol! + + override func setUp() { + super.setUp() + sut = VariantImageUrlExtractorService() + } + + override func tearDown() { + sut = nil + super.tearDown() + } + + func decodeJSON(_ json: String, to type: T.Type) -> T? { + guard let data = json.data(using: .utf8) else { return nil } + let decoder = JSONDecoder() + do { + let decodedObject = try decoder.decode(T.self, from: data) + return decodedObject + } catch { + print("JSON Decoding Error: \(error)") + return nil + } + } + + func testExtractUrls_modal_all_valid() { + let formVariantJSON = """ + { + "content": { + "background": { + "layers": [ + { + "action": { + "intentPayload": "{}", + "value": "https://images.pexels.com/photos/1624496/pexels-photo-1624496.jpeg", + "$type": "redirectUrl" + }, + "source": { + "value": "https://images.pexels.com/photos/1624496/pexels-photo-1624496.jpeg", + "$type": "url" + }, + "$type": "image" + }, + { + "action": { + "intentPayload": "{}", + "value": "https://mindbox-pushok.umbrellait.tech:444/?image=mindbox.png&broken=true&error=wait&speed=20", + "$type": "redirectUrl" + }, + "source": { + "value": "https://mindbox-pushok.umbrellait.tech:444/?image=mindbox.png&broken=true&error=wait&speed=20", + "$type": "url" + }, + "$type": "image" + } + ] + }, + "position": { + "margin": { + "kind": "dp", + "top": 0, + "right": 0, + "left": 0, + "bottom": 0 + }, + "gravity": { + "horizontal": "center", + "vertical": "bottom" + } + }, + "elements": [ + { + "color": "#000000", + "lineWidth": 1, + "size": { + "kind": "dp", + "width": 24, + "height": 24 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.02, + "right": 0.02, + "left": 0, + "bottom": 0 + } + }, + "$type": "closeButton" + } + ] + }, + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "$type": "modal" + } + """ + + guard let formVariant: MindboxFormVariant = decodeJSON(formVariantJSON, to: MindboxFormVariant.self) else { + XCTFail("Could not decode MindboxFormVariant from JSON") + return + } + + let extractedUrls = sut.extractImageURL(from: formVariant) + let expectedUrls = [ + "https://images.pexels.com/photos/1624496/pexels-photo-1624496.jpeg", + "https://mindbox-pushok.umbrellait.tech:444/?image=mindbox.png&broken=true&error=wait&speed=20", + ] + + XCTAssertEqual(extractedUrls, expectedUrls) + } + + func testExtractUrls_snackbar_all_valid() { + let formVariantJSON = """ + { + "content": { + "background": { + "layers": [ + { + "action": { + "intentPayload": "{}", + "value": "https://www.getmailbird.com/setup/assets/imgs/logos/gmail.com.webp", + "$type": "redirectUrl" + }, + "source": { + "value": "https://www.getmailbird.com/setup/assets/imgs/logos/gmail.com.webp", + "$type": "url" + }, + "$type": "image" + }, + { + "action": { + "intentPayload": "{}", + "value": "https://images.pexels.com/photos/1402787/pexels-photo-1402787.jpeg?auto=compress&cs=tinysrgb&w=6000&h=4000&dpr=2", + "$type": "redirectUrl" + }, + "source": { + "value": "https://images.pexels.com/photos/1402787/pexels-photo-1402787.jpeg?auto=compress&cs=tinysrgb&w=6000&h=4000&dpr=2", + "$type": "url" + }, + "$type": "image" + } + ] + }, + "position": { + "margin": { + "kind": "dp", + "top": 0, + "right": 0, + "left": 0, + "bottom": 0 + }, + "gravity": { + "horizontal": "center", + "vertical": "bottom" + } + }, + "elements": [ + { + "color": "#000000", + "lineWidth": 1, + "size": { + "kind": "dp", + "width": 24, + "height": 24 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.02, + "right": 0.02, + "left": 0, + "bottom": 0 + } + }, + "$type": "closeButton" + } + ] + }, + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "$type": "snackbar" + } + """ + + guard let formVariant: MindboxFormVariant = decodeJSON(formVariantJSON, to: MindboxFormVariant.self) else { + XCTFail("Could not decode MindboxFormVariant from JSON") + return + } + + let extractedUrls = sut.extractImageURL(from: formVariant) + let expectedUrls = [ + "https://www.getmailbird.com/setup/assets/imgs/logos/gmail.com.webp", + "https://images.pexels.com/photos/1402787/pexels-photo-1402787.jpeg?auto=compress&cs=tinysrgb&w=6000&h=4000&dpr=2", + ] + + XCTAssertEqual(extractedUrls, expectedUrls) + } +} diff --git a/MindboxTests/InApp/Tests/ModelValidatorTests/ContentElementPositionMarginValidatorTests.swift b/MindboxTests/InApp/Tests/ModelValidatorTests/ContentElementPositionMarginValidatorTests.swift deleted file mode 100644 index 1ff0dd94..00000000 --- a/MindboxTests/InApp/Tests/ModelValidatorTests/ContentElementPositionMarginValidatorTests.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// ContentElementPositionMarginValidatorTests.swift -// MindboxTests -// -// Created by vailence on 07.08.2023. -// Copyright © 2023 Mindbox. All rights reserved. -// - -import XCTest -@testable import Mindbox - -final class ContentElementPositionMarginValidatorTests: XCTestCase { - - var validator: ContentElementPositionMarginValidator! - var model: ContentElementPositionMargin! - - override func setUpWithError() throws { - validator = ContentElementPositionMarginValidator() - } - - override func tearDownWithError() throws { - validator = nil - model = nil - } - - func test_unknownCase_returnFalse() throws { - let model = ContentElementPositionMargin(kind: .unknown) - XCTAssertFalse(validator.isValid(item: model)) - } -} diff --git a/SDKVersionProvider/SDKVersionConfig.xcconfig b/SDKVersionProvider/SDKVersionConfig.xcconfig index 33935eff..2f2ba19a 100644 --- a/SDKVersionProvider/SDKVersionConfig.xcconfig +++ b/SDKVersionProvider/SDKVersionConfig.xcconfig @@ -1 +1 @@ -MARKETING_VERSION = 2.7.0 +MARKETING_VERSION = 2.8.0 diff --git a/SDKVersionProvider/SDKVersionProvider.swift b/SDKVersionProvider/SDKVersionProvider.swift index 1e6baf12..d752a873 100644 --- a/SDKVersionProvider/SDKVersionProvider.swift +++ b/SDKVersionProvider/SDKVersionProvider.swift @@ -8,5 +8,5 @@ import Foundation public class SDKVersionProvider { - public static let sdkVersion = "2.8.0-rc" + public static let sdkVersion = "2.8.0" }