this repo has no description
at oauth 166 lines 5.1 kB view raw
1// 2// IdentityResolverTests.swift 3// CoreATProtocol 4// 5// Created by Claude on 2026-01-02. 6// 7 8import Testing 9import Foundation 10@testable import CoreATProtocol 11 12@Suite("Identity Resolver Tests") 13struct IdentityResolverTests { 14 15 // MARK: - DID Document Tests 16 17 @Test("DID Document parses correctly") 18 func testDIDDocumentParsing() throws { 19 let json = """ 20 { 21 "@context": ["https://www.w3.org/ns/did/v1"], 22 "id": "did:plc:abc123", 23 "alsoKnownAs": ["at://alice.bsky.social"], 24 "verificationMethod": [{ 25 "id": "#atproto", 26 "type": "Multikey", 27 "controller": "did:plc:abc123", 28 "publicKeyMultibase": "zDnae..." 29 }], 30 "service": [{ 31 "id": "#atproto_pds", 32 "type": "AtprotoPersonalDataServer", 33 "serviceEndpoint": "https://bsky.social" 34 }] 35 } 36 """.data(using: .utf8)! 37 38 let document = try JSONDecoder().decode(DIDDocument.self, from: json) 39 40 #expect(document.id == "did:plc:abc123") 41 #expect(document.handle == "alice.bsky.social") 42 #expect(document.pdsEndpoint == "https://bsky.social") 43 #expect(document.verificationMethod?.count == 1) 44 #expect(document.service?.count == 1) 45 } 46 47 @Test("DID Document extracts handle from alsoKnownAs") 48 func testHandleExtraction() throws { 49 let document = DIDDocument( 50 id: "did:plc:test", 51 alsoKnownAs: ["at://user.example.com", "https://other.url"], 52 verificationMethod: nil, 53 service: nil 54 ) 55 56 #expect(document.handle == "user.example.com") 57 } 58 59 @Test("DID Document returns nil handle when missing") 60 func testMissingHandle() throws { 61 let document = DIDDocument( 62 id: "did:plc:test", 63 alsoKnownAs: nil, 64 verificationMethod: nil, 65 service: nil 66 ) 67 68 #expect(document.handle == nil) 69 } 70 71 @Test("PLC Directory response converts to DID Document") 72 func testPLCResponseConversion() throws { 73 let json = """ 74 { 75 "did": "did:plc:xyz789", 76 "alsoKnownAs": ["at://bob.test.com"], 77 "verificationMethods": { 78 "#atproto": "did:key:zDnae..." 79 }, 80 "services": { 81 "#atproto_pds": { 82 "type": "AtprotoPersonalDataServer", 83 "endpoint": "https://pds.example.com" 84 } 85 } 86 } 87 """.data(using: .utf8)! 88 89 let plcResponse = try JSONDecoder().decode(PLCDirectoryResponse.self, from: json) 90 let document = plcResponse.toDIDDocument() 91 92 #expect(document.id == "did:plc:xyz789") 93 #expect(document.alsoKnownAs?.contains("at://bob.test.com") == true) 94 } 95 96 // MARK: - Identity Error Tests 97 98 @Test("Identity errors are properly typed") 99 func testIdentityErrors() { 100 let handleError = IdentityError.invalidHandle("bad handle") 101 let pdsError = IdentityError.pdsNotFound 102 103 // Test error descriptions 104 #expect(String(describing: handleError).contains("invalidHandle")) 105 #expect(String(describing: pdsError).contains("pdsNotFound")) 106 } 107 108 // MARK: - Handle Validation Tests 109 110 @Test("Valid handles are accepted") 111 func testValidHandles() async throws { 112 // These should be valid handle formats 113 let validHandles = [ 114 "alice.bsky.social", 115 "user.example.com", 116 "test.subdomain.domain.tld" 117 ] 118 119 for handle in validHandles { 120 // Just testing the format is accepted 121 let normalized = handle.lowercased() 122 #expect(normalized.contains("."), "\(handle) should contain a dot") 123 } 124 } 125 126 // MARK: - Cache Tests 127 128 @Test("Cache is cleared correctly") 129 func testCacheClear() async { 130 let resolver = await IdentityResolver() 131 await resolver.clearCache() 132 // Should not throw 133 } 134 135 @Test("Cache TTL is configurable") 136 func testCacheTTL() async { 137 let resolver = await IdentityResolver() 138 let defaultTTL = await resolver.cacheTTL 139 #expect(defaultTTL == 600, "Default cache TTL should be 600 seconds") 140 141 await MainActor.run { 142 // Note: Need to access through proper isolation 143 } 144 } 145 146 // MARK: - Protected Resource Metadata Tests 147 148 @Test("Protected resource metadata parses correctly") 149 func testProtectedResourceMetadata() throws { 150 let json = """ 151 { 152 "resource": "https://bsky.social", 153 "authorization_servers": ["https://bsky.social"] 154 } 155 """.data(using: .utf8)! 156 157 let metadata = try JSONDecoder().decode( 158 IdentityResolver.ProtectedResourceMetadata.self, 159 from: json 160 ) 161 162 #expect(metadata.resource == "https://bsky.social") 163 #expect(metadata.authorizationServers.count == 1) 164 #expect(metadata.authorizationServers.first == "https://bsky.social") 165 } 166}