From dcccb128332738473b85d8fe68dc0374c86bac6c Mon Sep 17 00:00:00 2001 From: Sergei Semko <28645140+justSmK@users.noreply.github.com> Date: Thu, 14 May 2026 12:55:52 +0300 Subject: [PATCH] MOBILE-180: Trim `operationsDomain` config value before blank check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Android trims before the blank check, so whitespace-only operations from JSON config clears stored and falls through to init → default. iOS gated on isEmpty without trim, treated " " as invalid format, and kept the previous value indefinitely. Bring iOS in line. --- .../OperationsDomainConfigPolicy.swift | 3 ++- .../Network/OperationsURLRoutingTests.swift | 26 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/Mindbox/InAppMessages/Configuration/Services/OperationsDomainConfigPolicy.swift b/Mindbox/InAppMessages/Configuration/Services/OperationsDomainConfigPolicy.swift index f1b456c5..960ad9b9 100644 --- a/Mindbox/InAppMessages/Configuration/Services/OperationsDomainConfigPolicy.swift +++ b/Mindbox/InAppMessages/Configuration/Services/OperationsDomainConfigPolicy.swift @@ -27,7 +27,8 @@ enum OperationsDomainConfigPolicy { } static func action(for raw: String?, currentlyStored: String?) -> Action { - guard let value = raw, !value.isEmpty else { + let trimmed = raw?.trimmingCharacters(in: .whitespacesAndNewlines) + guard let value = trimmed, !value.isEmpty else { return currentlyStored == nil ? .keep : .clear } diff --git a/MindboxTests/Network/OperationsURLRoutingTests.swift b/MindboxTests/Network/OperationsURLRoutingTests.swift index 2407c542..230b9a85 100644 --- a/MindboxTests/Network/OperationsURLRoutingTests.swift +++ b/MindboxTests/Network/OperationsURLRoutingTests.swift @@ -278,10 +278,36 @@ struct OperationsURLRoutingTests { #expect(OperationsDomainConfigPolicy.action(for: "", currentlyStored: "https://old.ru") == .clear) } + @Test("Policy — clears on whitespace-only string when something is stored (Android parity)") + func policyClearsOnWhitespaceWhenStored() { + #expect(OperationsDomainConfigPolicy.action(for: " ", currentlyStored: "https://old.ru") == .clear) + #expect(OperationsDomainConfigPolicy.action(for: "\t\n ", currentlyStored: "https://old.ru") == .clear) + } + @Test("Policy — no-ops when nothing stored and nothing came") func policyKeepsOnNothingToChange() { #expect(OperationsDomainConfigPolicy.action(for: nil, currentlyStored: nil) == .keep) #expect(OperationsDomainConfigPolicy.action(for: "", currentlyStored: nil) == .keep) + #expect(OperationsDomainConfigPolicy.action(for: " ", currentlyStored: nil) == .keep) + } + + @Test("Policy — trims surrounding whitespace before evaluating value") + func policyTrimsSurroundingWhitespace() { + // Trimmed value matches stored after canonicalization → no-op. + #expect( + OperationsDomainConfigPolicy.action(for: " anonymizer.client.ru ", currentlyStored: "https://anonymizer.client.ru") + == .keep + ) + // Trimmed value differs from stored → save canonical form. + #expect( + OperationsDomainConfigPolicy.action(for: " new.client.ru ", currentlyStored: "https://old.ru") + == .save("https://new.client.ru") + ) + // Trimmed value with nothing stored → save canonical form. + #expect( + OperationsDomainConfigPolicy.action(for: " valid.host.ru ", currentlyStored: nil) + == .save("https://valid.host.ru") + ) } @Test("Policy — rejects format-broken incoming value (previous kept intact)")