// // IdentityResolverTests.swift // CoreATProtocol // // Created by Claude on 2026-01-02. // import Testing import Foundation @testable import CoreATProtocol @Suite("Identity Resolver Tests") struct IdentityResolverTests { // MARK: - DID Document Tests @Test("DID Document parses correctly") func testDIDDocumentParsing() throws { let json = """ { "@context": ["https://www.w3.org/ns/did/v1"], "id": "did:plc:abc123", "alsoKnownAs": ["at://alice.bsky.social"], "verificationMethod": [{ "id": "#atproto", "type": "Multikey", "controller": "did:plc:abc123", "publicKeyMultibase": "zDnae..." }], "service": [{ "id": "#atproto_pds", "type": "AtprotoPersonalDataServer", "serviceEndpoint": "https://bsky.social" }] } """.data(using: .utf8)! let document = try JSONDecoder().decode(DIDDocument.self, from: json) #expect(document.id == "did:plc:abc123") #expect(document.handle == "alice.bsky.social") #expect(document.pdsEndpoint == "https://bsky.social") #expect(document.verificationMethod?.count == 1) #expect(document.service?.count == 1) } @Test("DID Document extracts handle from alsoKnownAs") func testHandleExtraction() throws { let document = DIDDocument( id: "did:plc:test", alsoKnownAs: ["at://user.example.com", "https://other.url"], verificationMethod: nil, service: nil ) #expect(document.handle == "user.example.com") } @Test("DID Document returns nil handle when missing") func testMissingHandle() throws { let document = DIDDocument( id: "did:plc:test", alsoKnownAs: nil, verificationMethod: nil, service: nil ) #expect(document.handle == nil) } @Test("PLC Directory response converts to DID Document") func testPLCResponseConversion() throws { let json = """ { "did": "did:plc:xyz789", "alsoKnownAs": ["at://bob.test.com"], "verificationMethods": { "#atproto": "did:key:zDnae..." }, "services": { "#atproto_pds": { "type": "AtprotoPersonalDataServer", "endpoint": "https://pds.example.com" } } } """.data(using: .utf8)! let plcResponse = try JSONDecoder().decode(PLCDirectoryResponse.self, from: json) let document = plcResponse.toDIDDocument() #expect(document.id == "did:plc:xyz789") #expect(document.alsoKnownAs?.contains("at://bob.test.com") == true) } // MARK: - Identity Error Tests @Test("Identity errors are properly typed") func testIdentityErrors() { let handleError = IdentityError.invalidHandle("bad handle") let pdsError = IdentityError.pdsNotFound // Test error descriptions #expect(String(describing: handleError).contains("invalidHandle")) #expect(String(describing: pdsError).contains("pdsNotFound")) } // MARK: - Handle Validation Tests @Test("Valid handles are accepted") func testValidHandles() async throws { // These should be valid handle formats let validHandles = [ "alice.bsky.social", "user.example.com", "test.subdomain.domain.tld" ] for handle in validHandles { // Just testing the format is accepted let normalized = handle.lowercased() #expect(normalized.contains("."), "\(handle) should contain a dot") } } // MARK: - Cache Tests @Test("Cache is cleared correctly") func testCacheClear() async { let resolver = await IdentityResolver() await resolver.clearCache() // Should not throw } @Test("Cache TTL is configurable") func testCacheTTL() async { let resolver = await IdentityResolver() let defaultTTL = await resolver.cacheTTL #expect(defaultTTL == 600, "Default cache TTL should be 600 seconds") await MainActor.run { // Note: Need to access through proper isolation } } // MARK: - Protected Resource Metadata Tests @Test("Protected resource metadata parses correctly") func testProtectedResourceMetadata() throws { let json = """ { "resource": "https://bsky.social", "authorization_servers": ["https://bsky.social"] } """.data(using: .utf8)! let metadata = try JSONDecoder().decode( IdentityResolver.ProtectedResourceMetadata.self, from: json ) #expect(metadata.resource == "https://bsky.social") #expect(metadata.authorizationServers.count == 1) #expect(metadata.authorizationServers.first == "https://bsky.social") } }