import XCTest /// Smoke test eseguibile senza @testable import (validazione logica pura). final class ApiInstantTests: XCTestCase { func testOverlayKindMapping() { XCTAssertEqual(OverlayKindMapping.fromApi("basket"), "basket") XCTAssertEqual(OverlayKindMapping.fromApi("none"), "none") XCTAssertEqual(OverlayKindMapping.fromApi(nil), "volley") } func testRTMPUrlParser() { let target = RTMPUrlParserLogic.parse("rtmp://stream.example.com/live/match_abc-123") XCTAssertEqual(target?.connectURL, "rtmp://stream.example.com/live") XCTAssertEqual(target?.streamName, "match_abc-123") } func testRtmpIngestUrlRewritesDockerHostForLocalApi() { let resolved = RtmpIngestUrlLogic.resolve( "rtmp://mediamtx:1935/live/match_abc", apiBaseUrl: "http://localhost:3000" ) XCTAssertEqual(resolved, "rtmp://127.0.0.1:1935/live/match_abc") } func testRtmpIngestUrlKeepsProductionHost() { let url = "rtmp://www.matchlivetv.it:1935/live/match_abc" let resolved = RtmpIngestUrlLogic.resolve(url, apiBaseUrl: "https://www.matchlivetv.it") XCTAssertEqual(resolved, url) } } enum OverlayKindMapping { static func fromApi(_ value: String?) -> String { switch value?.lowercased() { case "none", "timer": return "none" case "basket": return "basket" case "timed": return "timed" case "racket": return "racket" default: return "volley" } } } enum RTMPUrlParserLogic { struct Target { let connectURL: String let streamName: String } static func parse(_ urlString: String) -> Target? { guard let url = URL(string: urlString), url.scheme?.hasPrefix("rtmp") == true else { return nil } let pathParts = url.path.split(separator: "/").map(String.init) guard pathParts.count >= 2 else { return nil } let app = pathParts.dropLast().joined(separator: "/") let streamName = pathParts.last ?? "" var connect = "rtmp://\(url.host ?? "")" if let port = url.port { connect += ":\(port)" } connect += "/\(app)" return Target(connectURL: connect, streamName: streamName) } } /// Copia della logica `RtmpIngestUrl` per test senza bundle Info.plist. enum RtmpIngestUrlLogic { private static let dockerInternalHosts: Set = ["mediamtx", "host.docker.internal"] static func resolve(_ urlString: String, apiBaseUrl: String) -> String { guard var components = URLComponents(string: urlString), let host = components.host?.lowercased() else { return urlString } let apiHost = URL(string: apiBaseUrl)?.host?.lowercased() let isLocalApi = apiHost.map { $0 == "localhost" || $0 == "127.0.0.1" || $0.hasSuffix(".local") } ?? false guard dockerInternalHosts.contains(host) || isLocalApi else { return urlString } let ingestHost: String if let apiHost, apiHost != "localhost", apiHost != "127.0.0.1" { ingestHost = apiHost } else { ingestHost = "127.0.0.1" } components.host = ingestHost if components.port == nil { components.port = 1935 } return components.url?.absoluteString ?? urlString } }