import Foundation import Testing @testable import VibeTunnel @Suite("ServerConfig Tests", .tags(.models)) struct ServerConfigTests { @Test("Creates valid HTTP URL") func hTTPURLCreation() { // Arrange let config = ServerConfig( host: "localhost", port: 8_888, name: nil, ) // Act let url = config.baseURL // Assert #expect(url.absoluteString == "http://localhost:8888") #expect(url.scheme == "http") #expect(url.host == "localhost") #expect(url.port == 8_888) } @Test("Creates valid URL with different ports") func urlWithDifferentPorts() { // Arrange let config = ServerConfig( host: "example.com", port: 443, name: "user", ) // Act let url = config.baseURL // Assert - baseURL always uses http:// #expect(url.absoluteString == "http://example.com:443") #expect(url.scheme == "http") #expect(url.host == "example.com") #expect(url.port == 443) } @Test("Display name uses custom name if provided") func displayNameWithCustomName() { let config = ServerConfig( host: "localhost", port: 8888, name: "My Server", ) #expect(config.displayName == "My Server") } @Test("Handles standard ports correctly") func standardPorts() { // HTTP standard port (80) let httpConfig = ServerConfig( host: "example.com", port: 80, ) #expect(httpConfig.baseURL.absoluteString == "http://example.com:80") // Another port let httpsConfig = ServerConfig( host: "example.com", port: 443, ) #expect(httpsConfig.baseURL.absoluteString == "http://example.com:443") } @Test("Encodes and decodes correctly") func codable() throws { // Arrange let originalConfig = ServerConfig( host: "test.local", port: 9_999, name: "testuser", ) // Act let encoder = JSONEncoder() let data = try encoder.encode(originalConfig) let decoder = JSONDecoder() let decodedConfig = try decoder.decode(ServerConfig.self, from: data) // Assert #expect(decodedConfig.host == originalConfig.host) #expect(decodedConfig.port == originalConfig.port) #expect(decodedConfig.name == originalConfig.name) } @Test("Optional credentials encoding") func optionalCredentials() throws { // Config without credentials let configNoAuth = ServerConfig( host: "public.server", port: 8_080, ) let data = try JSONEncoder().encode(configNoAuth) let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] #expect(json?["name"] == nil) } @Test("Equality comparison") func equality() { let config1 = ServerConfig( host: "localhost", port: 8_888, ) let config2 = ServerConfig( host: "localhost", port: 8_888, ) let config3 = ServerConfig( host: "localhost", port: 9_999, // Different port ) #expect(config1 == config2) #expect(config1 != config3) } @Test("Handles IPv6 addresses") func iPv6Address() { let config = ServerConfig( host: "::1", port: 8_888, ) let url = config.baseURL // IPv6 addresses need brackets in URLs #expect(url.absoluteString == "http://[::1]:8888" || url.absoluteString == "http://::1:8888") #expect(url.port == 8888) } @Test("Handles domain with subdomain") func subdomainHandling() { let config = ServerConfig( host: "api.staging.example.com", port: 443, ) let url = config.baseURL #expect(url.absoluteString == "http://api.staging.example.com:443") #expect(url.host == "api.staging.example.com") } @Test("Display name formatting") func testDisplayName() { // Without custom name let simpleConfig = ServerConfig( host: "localhost", port: 8_888, ) #expect(simpleConfig.displayName == "localhost:8888") // With custom name let namedConfig = ServerConfig( host: "secure.example.com", port: 443, name: "Production Server" ) #expect(namedConfig.displayName == "Production Server") } @Test("JSON representation matches expected format") func jSONFormat() throws { // Arrange let config = ServerConfig( host: "test.server", port: 3_000, name: "user", ) // Act let encoder = JSONEncoder() encoder.outputFormatting = .sortedKeys let data = try encoder.encode(config) let jsonString = String(data: data, encoding: .utf8)! // Assert #expect(jsonString.contains("\"host\":\"test.server\"")) #expect(jsonString.contains("\"port\":3000")) #expect(jsonString.contains("\"name\":\"user\"")) } } // MARK: - Integration Tests @Suite("ServerConfig Integration Tests", .tags(.models, .integration)) struct ServerConfigIntegrationTests { @Test("Round-trip through UserDefaults") func userDefaultsPersistence() throws { // Arrange let config = TestFixtures.sslServerConfig let key = "test_server_config" // Clear any existing value UserDefaults.standard.removeObject(forKey: key) // Act - Save let encoder = JSONEncoder() let data = try encoder.encode(config) UserDefaults.standard.set(data, forKey: key) // Act - Load guard let loadedData = UserDefaults.standard.data(forKey: key) else { Issue.record("Failed to load data from UserDefaults") return } let decoder = JSONDecoder() let loadedConfig = try decoder.decode(ServerConfig.self, from: loadedData) // Assert #expect(loadedConfig == config) // Cleanup UserDefaults.standard.removeObject(forKey: key) } }