Files
yattee/YatteeTests/CredentialsTests.swift
2026-02-08 18:33:56 +01:00

339 lines
11 KiB
Swift

//
// CredentialsTests.swift
// YatteeTests
//
// Tests for credential managers (Invidious and Piped).
//
import Testing
import Foundation
@testable import Yattee
// MARK: - PipedCredentialsManager Tests
@Suite("PipedCredentialsManager Tests")
@MainActor
struct PipedCredentialsManagerTests {
private func createTestInstance() -> Instance {
Instance(type: .piped, url: URL(string: "https://piped.test.example")!)
}
@Test("setCredential stores token and updates loggedInInstanceIDs")
func setCredentialStoresToken() {
let manager = PipedCredentialsManager()
let instance = createTestInstance()
let token = "test-auth-token-\(UUID().uuidString)"
manager.setCredential(token, for: instance)
#expect(manager.loggedInInstanceIDs.contains(instance.id))
// Cleanup
manager.deleteCredential(for: instance)
}
@Test("credential retrieves stored token")
func credentialRetrievesToken() {
let manager = PipedCredentialsManager()
let instance = createTestInstance()
let token = "test-auth-token-\(UUID().uuidString)"
manager.setCredential(token, for: instance)
let retrieved = manager.credential(for: instance)
#expect(retrieved == token)
// Cleanup
manager.deleteCredential(for: instance)
}
@Test("credential returns nil for unknown instance")
func credentialReturnsNilForUnknown() {
let manager = PipedCredentialsManager()
let instance = createTestInstance()
let retrieved = manager.credential(for: instance)
#expect(retrieved == nil)
}
@Test("deleteCredential removes token and updates loggedInInstanceIDs")
func deleteCredentialRemovesToken() {
let manager = PipedCredentialsManager()
let instance = createTestInstance()
let token = "test-auth-token-\(UUID().uuidString)"
manager.setCredential(token, for: instance)
#expect(manager.loggedInInstanceIDs.contains(instance.id))
manager.deleteCredential(for: instance)
#expect(!manager.loggedInInstanceIDs.contains(instance.id))
#expect(manager.credential(for: instance) == nil)
}
@Test("isLoggedIn returns true when logged in")
func isLoggedInReturnsTrue() {
let manager = PipedCredentialsManager()
let instance = createTestInstance()
let token = "test-auth-token-\(UUID().uuidString)"
manager.setCredential(token, for: instance)
#expect(manager.isLoggedIn(for: instance) == true)
// Cleanup
manager.deleteCredential(for: instance)
}
@Test("isLoggedIn returns false when not logged in")
func isLoggedInReturnsFalse() {
let manager = PipedCredentialsManager()
let instance = createTestInstance()
#expect(manager.isLoggedIn(for: instance) == false)
}
@Test("refreshLoginStatus syncs loggedInInstanceIDs with Keychain")
func refreshLoginStatusSyncs() {
let manager = PipedCredentialsManager()
let instance = createTestInstance()
let token = "test-auth-token-\(UUID().uuidString)"
// Store credential
manager.setCredential(token, for: instance)
// Simulate stale state by manually removing from tracked set
// (This tests the refresh mechanism)
let freshManager = PipedCredentialsManager()
#expect(!freshManager.loggedInInstanceIDs.contains(instance.id))
freshManager.refreshLoginStatus(for: instance)
#expect(freshManager.loggedInInstanceIDs.contains(instance.id))
// Cleanup
manager.deleteCredential(for: instance)
}
@Test("setCredential updates existing token")
func setCredentialUpdatesExisting() {
let manager = PipedCredentialsManager()
let instance = createTestInstance()
let token1 = "test-auth-token-1-\(UUID().uuidString)"
let token2 = "test-auth-token-2-\(UUID().uuidString)"
manager.setCredential(token1, for: instance)
#expect(manager.credential(for: instance) == token1)
manager.setCredential(token2, for: instance)
#expect(manager.credential(for: instance) == token2)
// Cleanup
manager.deleteCredential(for: instance)
}
@Test("Multiple instances have separate credentials")
func multipleInstancesSeparateCredentials() {
let manager = PipedCredentialsManager()
let instance1 = Instance(type: .piped, url: URL(string: "https://piped1.test.example")!)
let instance2 = Instance(type: .piped, url: URL(string: "https://piped2.test.example")!)
let token1 = "token-1-\(UUID().uuidString)"
let token2 = "token-2-\(UUID().uuidString)"
manager.setCredential(token1, for: instance1)
manager.setCredential(token2, for: instance2)
#expect(manager.credential(for: instance1) == token1)
#expect(manager.credential(for: instance2) == token2)
#expect(manager.loggedInInstanceIDs.count >= 2)
// Cleanup
manager.deleteCredential(for: instance1)
manager.deleteCredential(for: instance2)
}
}
// MARK: - InvidiousCredentialsManager Tests
@Suite("InvidiousCredentialsManager Tests")
@MainActor
struct InvidiousCredentialsManagerTests {
private func createTestInstance() -> Instance {
Instance(type: .invidious, url: URL(string: "https://invidious.test.example")!)
}
@Test("setSID stores session and updates loggedInInstanceIDs")
func setSIDStoresSession() {
let manager = InvidiousCredentialsManager()
let instance = createTestInstance()
let sid = "test-session-id-\(UUID().uuidString)"
manager.setSID(sid, for: instance)
#expect(manager.loggedInInstanceIDs.contains(instance.id))
// Cleanup
manager.deleteSID(for: instance)
}
@Test("sid retrieves stored session")
func sidRetrievesSession() {
let manager = InvidiousCredentialsManager()
let instance = createTestInstance()
let sid = "test-session-id-\(UUID().uuidString)"
manager.setSID(sid, for: instance)
let retrieved = manager.sid(for: instance)
#expect(retrieved == sid)
// Cleanup
manager.deleteSID(for: instance)
}
@Test("sid returns nil for unknown instance")
func sidReturnsNilForUnknown() {
let manager = InvidiousCredentialsManager()
let instance = createTestInstance()
let retrieved = manager.sid(for: instance)
#expect(retrieved == nil)
}
@Test("deleteSID removes session and updates loggedInInstanceIDs")
func deleteSIDRemovesSession() {
let manager = InvidiousCredentialsManager()
let instance = createTestInstance()
let sid = "test-session-id-\(UUID().uuidString)"
manager.setSID(sid, for: instance)
#expect(manager.loggedInInstanceIDs.contains(instance.id))
manager.deleteSID(for: instance)
#expect(!manager.loggedInInstanceIDs.contains(instance.id))
#expect(manager.sid(for: instance) == nil)
}
@Test("Protocol methods delegate correctly")
func protocolMethodsDelegate() {
let manager = InvidiousCredentialsManager()
let instance = createTestInstance()
let sid = "test-session-id-\(UUID().uuidString)"
// Test setCredential -> setSID
manager.setCredential(sid, for: instance)
#expect(manager.sid(for: instance) == sid)
// Test credential -> sid
#expect(manager.credential(for: instance) == sid)
// Test deleteCredential -> deleteSID
manager.deleteCredential(for: instance)
#expect(manager.sid(for: instance) == nil)
}
@Test("isLoggedIn returns correct state")
func isLoggedInReturnsCorrectState() {
let manager = InvidiousCredentialsManager()
let instance = createTestInstance()
let sid = "test-session-id-\(UUID().uuidString)"
#expect(manager.isLoggedIn(for: instance) == false)
manager.setSID(sid, for: instance)
#expect(manager.isLoggedIn(for: instance) == true)
manager.deleteSID(for: instance)
#expect(manager.isLoggedIn(for: instance) == false)
}
@Test("Thumbnail cache stores and retrieves URLs")
func thumbnailCacheWorks() {
let manager = InvidiousCredentialsManager()
let channelID = "UC\(UUID().uuidString.prefix(22))"
let thumbnailURL = URL(string: "https://example.com/thumb.jpg")!
manager.setThumbnailURL(thumbnailURL, forChannelID: channelID)
let retrieved = manager.thumbnailURL(forChannelID: channelID)
#expect(retrieved == thumbnailURL)
// Cleanup
manager.clearThumbnailCache()
}
@Test("uncachedChannelIDs filters correctly")
func uncachedChannelIDsFilters() {
let manager = InvidiousCredentialsManager()
let cachedID = "UCcached\(UUID().uuidString.prefix(16))"
let uncachedID = "UCuncached\(UUID().uuidString.prefix(14))"
manager.setThumbnailURL(URL(string: "https://example.com/thumb.jpg")!, forChannelID: cachedID)
let uncached = manager.uncachedChannelIDs(from: [cachedID, uncachedID])
#expect(uncached.count == 1)
#expect(uncached.contains(uncachedID))
#expect(!uncached.contains(cachedID))
// Cleanup
manager.clearThumbnailCache()
}
@Test("setThumbnailURLs batches correctly")
func setThumbnailURLsBatches() {
let manager = InvidiousCredentialsManager()
let id1 = "UC1\(UUID().uuidString.prefix(19))"
let id2 = "UC2\(UUID().uuidString.prefix(19))"
let url1 = URL(string: "https://example.com/thumb1.jpg")!
let url2 = URL(string: "https://example.com/thumb2.jpg")!
manager.setThumbnailURLs([id1: url1, id2: url2])
#expect(manager.thumbnailURL(forChannelID: id1) == url1)
#expect(manager.thumbnailURL(forChannelID: id2) == url2)
// Cleanup
manager.clearThumbnailCache()
}
}
// MARK: - InstanceCredentialsManager Protocol Tests
@Suite("InstanceCredentialsManager Protocol Tests")
@MainActor
struct InstanceCredentialsManagerProtocolTests {
@Test("PipedCredentialsManager conforms to protocol")
func pipedConformsToProtocol() {
let manager: InstanceCredentialsManager = PipedCredentialsManager()
let instance = Instance(type: .piped, url: URL(string: "https://piped.test.example")!)
let token = "protocol-test-\(UUID().uuidString)"
manager.setCredential(token, for: instance)
#expect(manager.credential(for: instance) == token)
#expect(manager.isLoggedIn(for: instance) == true)
manager.deleteCredential(for: instance)
#expect(manager.isLoggedIn(for: instance) == false)
}
@Test("InvidiousCredentialsManager conforms to protocol")
func invidiousConformsToProtocol() {
let manager: InstanceCredentialsManager = InvidiousCredentialsManager()
let instance = Instance(type: .invidious, url: URL(string: "https://invidious.test.example")!)
let sid = "protocol-test-\(UUID().uuidString)"
manager.setCredential(sid, for: instance)
#expect(manager.credential(for: instance) == sid)
#expect(manager.isLoggedIn(for: instance) == true)
manager.deleteCredential(for: instance)
#expect(manager.isLoggedIn(for: instance) == false)
}
}