diff --git a/apps/ios/Sources/Settings/SettingsNetworkingHelpers.swift b/apps/ios/Sources/Settings/SettingsNetworkingHelpers.swift new file mode 100644 index 000000000..f061ff9a2 --- /dev/null +++ b/apps/ios/Sources/Settings/SettingsNetworkingHelpers.swift @@ -0,0 +1,40 @@ +import Foundation + +struct SettingsHostPort: Equatable { + var host: String + var port: Int +} + +enum SettingsNetworkingHelpers { + static func parseHostPort(from address: String) -> SettingsHostPort? { + let trimmed = address.trimmingCharacters(in: .whitespacesAndNewlines) + guard !trimmed.isEmpty else { return nil } + + if trimmed.hasPrefix("["), + let close = trimmed.firstIndex(of: "]"), + close < trimmed.endIndex + { + let host = String(trimmed[trimmed.index(after: trimmed.startIndex).. String { + if let host, let port { + let needsBrackets = host.contains(":") && !host.hasPrefix("[") && !host.hasSuffix("]") + let hostPart = needsBrackets ? "[\(host)]" : host + return "http://\(hostPart):\(port)" + } + return "http://\(fallback)" + } +} diff --git a/apps/ios/Sources/Settings/SettingsTab.swift b/apps/ios/Sources/Settings/SettingsTab.swift index 9395048b4..5c2a1b8e3 100644 --- a/apps/ios/Sources/Settings/SettingsTab.swift +++ b/apps/ios/Sources/Settings/SettingsTab.swift @@ -400,40 +400,11 @@ struct SettingsTab: View { return en0 ?? fallback } - private struct HostPort: Equatable { - var host: String - var port: Int - } - - private static func parseHostPort(from address: String) -> HostPort? { - let trimmed = address.trimmingCharacters(in: .whitespacesAndNewlines) - guard !trimmed.isEmpty else { return nil } - - if trimmed.hasPrefix("["), - let close = trimmed.firstIndex(of: "]"), - close < trimmed.endIndex - { - let host = String(trimmed[trimmed.index(after: trimmed.startIndex).. SettingsHostPort? { + SettingsNetworkingHelpers.parseHostPort(from: address) } private static func httpURLString(host: String?, port: Int?, fallback: String) -> String { - if let host, let port { - let needsBrackets = host.contains(":") && !host.hasPrefix("[") && !host.hasSuffix("]") - let hostPart = needsBrackets ? "[\(host)]" : host - return "http://\(hostPart):\(port)" - } - return "http://\(fallback)" + SettingsNetworkingHelpers.httpURLString(host: host, port: port, fallback: fallback) } } diff --git a/apps/ios/Tests/SettingsNetworkingHelpersTests.swift b/apps/ios/Tests/SettingsNetworkingHelpersTests.swift new file mode 100644 index 000000000..4ce123a87 --- /dev/null +++ b/apps/ios/Tests/SettingsNetworkingHelpersTests.swift @@ -0,0 +1,46 @@ +import Testing +@testable import Clawdis + +@Suite struct SettingsNetworkingHelpersTests { + @Test func parseHostPortParsesIPv4() { + #expect(SettingsNetworkingHelpers.parseHostPort(from: "127.0.0.1:8080") == .init(host: "127.0.0.1", port: 8080)) + } + + @Test func parseHostPortParsesHostnameAndTrims() { + #expect(SettingsNetworkingHelpers.parseHostPort(from: " example.com:80 \n") == .init(host: "example.com", port: 80)) + } + + @Test func parseHostPortParsesBracketedIPv6() { + #expect( + SettingsNetworkingHelpers.parseHostPort(from: "[2001:db8::1]:443") == + .init(host: "2001:db8::1", port: 443)) + } + + @Test func parseHostPortRejectsMissingPort() { + #expect(SettingsNetworkingHelpers.parseHostPort(from: "example.com") == nil) + #expect(SettingsNetworkingHelpers.parseHostPort(from: "[2001:db8::1]") == nil) + } + + @Test func parseHostPortRejectsInvalidPort() { + #expect(SettingsNetworkingHelpers.parseHostPort(from: "example.com:lol") == nil) + #expect(SettingsNetworkingHelpers.parseHostPort(from: "[2001:db8::1]:lol") == nil) + } + + @Test func httpURLStringFormatsIPv4AndPort() { + #expect(SettingsNetworkingHelpers.httpURLString(host: "127.0.0.1", port: 8080, fallback: "fallback") == "http://127.0.0.1:8080") + } + + @Test func httpURLStringBracketsIPv6() { + #expect(SettingsNetworkingHelpers.httpURLString(host: "2001:db8::1", port: 8080, fallback: "fallback") == "http://[2001:db8::1]:8080") + } + + @Test func httpURLStringLeavesAlreadyBracketedIPv6() { + #expect(SettingsNetworkingHelpers.httpURLString(host: "[2001:db8::1]", port: 8080, fallback: "fallback") == "http://[2001:db8::1]:8080") + } + + @Test func httpURLStringFallsBackWhenMissingHostOrPort() { + #expect(SettingsNetworkingHelpers.httpURLString(host: nil, port: 80, fallback: "x") == "http://x") + #expect(SettingsNetworkingHelpers.httpURLString(host: "example.com", port: nil, fallback: "y") == "http://y") + } +} +