import Testing @testable import Kordant import BackgroundTasks import SwiftUI import Network // MARK: - SyncStatus Tests struct SyncStatusTests { @Test("SyncStatus defaults are correct") func defaults() { let status = SyncStatus() #expect(status.lastSuccessfulSync == nil) #expect(status.lastSyncAttempt == nil) #expect(status.currentSyncState == .idle) #expect(status.syncError == nil) #expect(status.totalBytesTransferred == 0) #expect(status.deltaSyncSavings == 0) #expect(status.isLowPowerMode == false) #expect(status.isOffline == false) #expect(status.syncProgress == 0.0) #expect(status.syncStageDescription == "") } @Test("SyncStatus lastSyncDescription shows Never when no sync") func lastSyncDescriptionNever() { let status = SyncStatus() #expect(status.lastSyncDescription == "Never") } @Test("SyncStatus lastSyncDescription shows relative time") func lastSyncDescriptionRelative() { var status = SyncStatus() status.lastSuccessfulSync = Date() // Should show something like "now" or "0s" #expect(!status.lastSyncDescription.isEmpty) #expect(status.lastSyncDescription != "Never") } @Test("SyncStatus bytesTransferredString formats bytes") func bytesTransferredString() { var status = SyncStatus() status.totalBytesTransferred = 1024 #expect(status.bytesTransferredString == "1 KB") } @Test("SyncStatus deltaSyncSavingsPercent is 0 when no data") func deltaSyncSavingsZero() { let status = SyncStatus() #expect(status.deltaSyncSavingsPercent == 0) } @Test("SyncStatus deltaSyncSavingsPercent calculates correctly") func deltaSyncSavingsCalculation() { var status = SyncStatus() status.totalBytesTransferred = 500 status.deltaSyncSavings = 500 // 500 / (500 + 500) * 100 = 50% #expect(status.deltaSyncSavingsPercent == 50.0) } @Test("SyncStatus equality compares key fields") func equality() { var status1 = SyncStatus() var status2 = SyncStatus() status1.lastSuccessfulSync = Date() status2.lastSuccessfulSync = status1.lastSuccessfulSync status1.currentSyncState = .completed status2.currentSyncState = .completed #expect(status1 == status2) } @Test("SyncStatus progress fields do not affect equality") func equalityIgnoresProgress() { var status1 = SyncStatus() var status2 = SyncStatus() status1.syncProgress = 0.5 status1.syncStageDescription = "Fetching..." status2.syncProgress = 0.8 status2.syncStageDescription = "Saving..." // Progress fields are transient and should not affect equality #expect(status1 == status2) } } // MARK: - SyncStatusManager Tests @MainActor struct SyncStatusManagerTests { @Test("SyncStatusManager starts with idle state") func initialState() { let manager = SyncStatusManager(defaults: UserDefaults(suiteName: UUID().uuidString)!) #expect(manager.status.currentSyncState == .idle) #expect(manager.status.syncProgress == 0.0) #expect(manager.status.syncStageDescription == "") } @Test("SyncStatusManager startSync updates state") func startSync() { let manager = SyncStatusManager(defaults: UserDefaults(suiteName: UUID().uuidString)!) manager.startSync(.appRefresh) #expect(manager.status.currentSyncState == .syncing) #expect(manager.status.lastSyncAttempt != nil) #expect(manager.status.lastSyncOperation == .appRefresh) #expect(manager.status.syncError == nil) #expect(manager.status.syncProgress == 0.0) } @Test("SyncStatusManager completeSync updates state") func completeSync() { let manager = SyncStatusManager(defaults: UserDefaults(suiteName: UUID().uuidString)!) manager.startSync(.appRefresh) manager.completeSync(bytesTransferred: 1024, deltaSavings: 512) #expect(manager.status.currentSyncState == .completed) #expect(manager.status.lastSuccessfulSync != nil) #expect(manager.status.syncError == nil) #expect(manager.status.totalBytesTransferred == 1024) #expect(manager.status.deltaSyncSavings == 512) #expect(manager.status.syncProgress == 1.0) } @Test("SyncStatusManager failSync updates state") func failSync() { let manager = SyncStatusManager(defaults: UserDefaults(suiteName: UUID().uuidString)!) manager.startSync(.appRefresh) manager.failSync(with: "Network error") #expect(manager.status.currentSyncState == .failed) #expect(manager.status.syncError == "Network error") #expect(manager.status.syncProgress == 0.0) } @Test("SyncStatusManager setOffline updates state") func setOffline() { let manager = SyncStatusManager(defaults: UserDefaults(suiteName: UUID().uuidString)!) manager.setOffline(true) #expect(manager.status.isOffline == true) #expect(manager.status.currentSyncState == .offline) manager.setOffline(false) #expect(manager.status.isOffline == false) #expect(manager.status.currentSyncState == .idle) } @Test("SyncStatusManager accumulates bytes across syncs") func accumulateBytes() { let manager = SyncStatusManager(defaults: UserDefaults(suiteName: UUID().uuidString)!) manager.completeSync(bytesTransferred: 100, deltaSavings: 50) manager.completeSync(bytesTransferred: 200, deltaSavings: 100) #expect(manager.status.totalBytesTransferred == 300) #expect(manager.status.deltaSyncSavings == 150) } @Test("SyncStatusManager persists and restores state") func persistence() { let defaults = UserDefaults(suiteName: UUID().uuidString)! let manager1 = SyncStatusManager(defaults: defaults) manager1.completeSync(bytesTransferred: 500, deltaSavings: 200) let manager2 = SyncStatusManager(defaults: defaults) #expect(manager2.status.totalBytesTransferred == 500) #expect(manager2.status.deltaSyncSavings == 200) } @Test("SyncStatusManager resets syncing state on launch") func resetSyncingStateOnLaunch() { let defaults = UserDefaults(suiteName: UUID().uuidString)! let manager1 = SyncStatusManager(defaults: defaults) manager1.startSync(.appRefresh) // Simulate crash — state is syncing let manager2 = SyncStatusManager(defaults: defaults) // Should reset to idle #expect(manager2.status.currentSyncState == .idle) } @Test("SyncStatusManager resets progress on launch") func resetProgressOnLaunch() { let defaults = UserDefaults(suiteName: UUID().uuidString)! let manager1 = SyncStatusManager(defaults: defaults) manager1.startSync(.appRefresh) manager1.updateProgress(0.5, stage: "Fetching alerts...") let manager2 = SyncStatusManager(defaults: defaults) // Progress should be reset on launch #expect(manager2.status.syncProgress == 0.0) #expect(manager2.status.syncStageDescription == "") } @Test("SyncStatusManager updateProgress updates progress fields") func updateProgress() { let manager = SyncStatusManager(defaults: UserDefaults(suiteName: UUID().uuidString)!) manager.startSync(.appRefresh) manager.updateProgress(0.3, stage: "Fetching alerts...") #expect(manager.status.syncProgress == 0.3) #expect(manager.status.syncStageDescription == "Fetching alerts...") } } // MARK: - BackgroundTaskID Tests struct BackgroundTaskIDTests { @Test("BackgroundTaskID has correct raw values") func rawValues() { #expect(BackgroundTaskID.appRefresh.rawValue == "com.frenocorp.kordant.refresh") #expect(BackgroundTaskID.darkWebScan.rawValue == "com.frenocorp.kordant.darkWebScan") #expect(BackgroundTaskID.spamDatabaseUpdate.rawValue == "com.frenocorp.kordant.spamDatabaseUpdate") } @Test("BackgroundTaskID isProcessingTask returns correct values") func isProcessingTask() { #expect(BackgroundTaskID.appRefresh.isProcessingTask == false) #expect(BackgroundTaskID.darkWebScan.isProcessingTask == true) #expect(BackgroundTaskID.spamDatabaseUpdate.isProcessingTask == true) } } // MARK: - BackgroundSyncService Tests struct BackgroundSyncServiceTests { @Test("BackgroundSyncService minimumFetchInterval is 15 minutes") func minimumFetchInterval() { #expect(BackgroundSyncService.minimumFetchInterval == 15 * 60) } @Test("BackgroundSyncService lowPowerFetchInterval is 30 minutes") func lowPowerFetchInterval() { #expect(BackgroundSyncService.lowPowerFetchInterval == 30 * 60) } @Test("DeltaSyncResult hasChanges is true when any data changed") func deltaSyncResultHasChanges() { let result = DeltaSyncResult( alertsChanged: true, exposuresChanged: false, watchlistChanged: false, bytesTransferred: 100, deltaSavings: 50, newAlerts: [], newExposures: [] ) #expect(result.hasChanges == true) } @Test("DeltaSyncResult hasChanges is false when nothing changed") func deltaSyncResultNoChanges() { let result = DeltaSyncResult( alertsChanged: false, exposuresChanged: false, watchlistChanged: false, bytesTransferred: 0, deltaSavings: 0, newAlerts: [], newExposures: [] ) #expect(result.hasChanges == false) } @Test("SyncOperation raw values are correct") func syncOperationRawValues() { #expect(SyncOperation.appRefresh.rawValue == "app_refresh") #expect(SyncOperation.darkWebScan.rawValue == "dark_web_scan") #expect(SyncOperation.spamDatabaseUpdate.rawValue == "spam_database_update") #expect(SyncOperation.pushNotificationSync.rawValue == "push_notification_sync") #expect(SyncOperation.manual.rawValue == "manual") } @Test("SyncState raw values are correct") func syncStateRawValues() { #expect(SyncState.idle.rawValue == "idle") #expect(SyncState.syncing.rawValue == "syncing") #expect(SyncState.completed.rawValue == "completed") #expect(SyncState.failed.rawValue == "failed") #expect(SyncState.offline.rawValue == "offline") } @Test("SyncProgressStage fetching has correct description") func progressStageFetching() { let progress = SyncProgress( operation: .appRefresh, stage: .fetching(label: "alerts"), fractionCompleted: 0.3, estimatedRemaining: nil ) #expect(progress.description == "Fetching alerts...") } @Test("SyncProgressStage processing has correct description") func progressStageProcessing() { let progress = SyncProgress( operation: .appRefresh, stage: .processing, fractionCompleted: 0.7, estimatedRemaining: nil ) #expect(progress.description == "Processing data...") } @Test("SyncProgressStage saving has correct description") func progressStageSaving() { let progress = SyncProgress( operation: .appRefresh, stage: .saving, fractionCompleted: 0.9, estimatedRemaining: nil ) #expect(progress.description == "Saving data...") } @Test("SyncProgressStage completed has correct description") func progressStageCompleted() { let progress = SyncProgress( operation: .appRefresh, stage: .completed, fractionCompleted: 1.0, estimatedRemaining: nil ) #expect(progress.description == "Sync completed") } @Test("SyncProgressStage failed has correct description") func progressStageFailed() { let progress = SyncProgress( operation: .appRefresh, stage: .failed(message: "Network error"), fractionCompleted: 0.0, estimatedRemaining: nil ) #expect(progress.description == "Sync failed: Network error") } @Test("DeltaFetchResult is generic and works with any type") func deltaFetchResultGeneric() { let result: DeltaFetchResult = DeltaFetchResult( changed: true, data: "test", bytes: 1024, savings: 512 ) #expect(result.changed == true) #expect(result.data == "test") #expect(result.bytes == 1024) #expect(result.savings == 512) } } // MARK: - BackgroundTaskScheduler Tests struct BackgroundTaskSchedulerTests { @Test("BackgroundTaskScheduler minimumRefreshInterval is 15 minutes") func minimumRefreshInterval() { let scheduler = BackgroundTaskScheduler() #expect(scheduler.minimumRefreshInterval == 15 * 60) } @Test("BackgroundTaskScheduler lowPowerRefreshInterval is 30 minutes") func lowPowerRefreshInterval() { let scheduler = BackgroundTaskScheduler() #expect(scheduler.lowPowerRefreshInterval == 30 * 60) } @Test("BackgroundTaskScheduler darkWebScanInterval is 6 hours") func darkWebScanInterval() { let scheduler = BackgroundTaskScheduler() #expect(scheduler.darkWebScanInterval == 6 * 60 * 60) } @Test("BackgroundTaskScheduler spamUpdateInterval is 24 hours") func spamUpdateInterval() { let scheduler = BackgroundTaskScheduler() #expect(scheduler.spamUpdateInterval == 24 * 60 * 60) } @Test("BackgroundTaskScheduler lowPowerDarkWebScanInterval is 12 hours") func lowPowerDarkWebScanInterval() { let scheduler = BackgroundTaskScheduler() #expect(scheduler.lowPowerDarkWebScanInterval == 12 * 60 * 60) } @Test("BackgroundTaskScheduler lowPowerSpamUpdateInterval is 48 hours") func lowPowerSpamUpdateInterval() { let scheduler = BackgroundTaskScheduler() #expect(scheduler.lowPowerSpamUpdateInterval == 48 * 60 * 60) } @Test("BackgroundTaskScheduler should not defer when recently synced in normal mode") func shouldNotDeferNormalMode() { let scheduler = BackgroundTaskScheduler() #expect(scheduler.shouldDeferBackgroundTasks() == false) } @Test("BackgroundTaskScheduler registerAllTasks does not crash") func registerAllTasks() { let scheduler = BackgroundTaskScheduler() // Should not throw scheduler.registerAllTasks() } @Test("BackgroundTaskScheduler scheduleAllTasks does not crash") func scheduleAllTasks() { let scheduler = BackgroundTaskScheduler() // Should not throw scheduler.scheduleAllTasks() } @Test("BackgroundTaskScheduler currentlyHasRunningTask starts as false") func currentlyHasRunningTask() { let scheduler = BackgroundTaskScheduler() #expect(scheduler.currentlyHasRunningTask == false) } @Test("BackgroundTaskScheduler task counters start at zero") func taskCountersStartAtZero() { let scheduler = BackgroundTaskScheduler() #expect(scheduler.tasksCompleted == 0) #expect(scheduler.tasksExpired == 0) } } // MARK: - ETagCacheEntry Tests struct ETagCacheEntryTests { @Test("ETagCacheEntry is not stale when fresh") func freshEntry() { let entry = ETagCacheEntry(etag: "abc123", lastModified: "2024-01-01", timestamp: Date()) #expect(entry.isStale == false) } @Test("ETagCacheEntry is stale after 10 minutes") func staleEntry() { let entry = ETagCacheEntry( etag: "abc123", lastModified: "2024-01-01", timestamp: Date().addingTimeInterval(-601) // Just over 10 minutes ) #expect(entry.isStale == true) } @Test("ETagCacheEntry is stale at exactly 10 minutes") func exactlyStale() { let entry = ETagCacheEntry( etag: "abc123", lastModified: "2024-01-01", timestamp: Date().addingTimeInterval(-600) // Exactly 10 minutes ) #expect(entry.isStale == true) } @Test("ETagCacheEntry is Codable") func codable() throws { let entry = ETagCacheEntry(etag: "abc123", lastModified: "2024-01-01", timestamp: Date()) let data = try JSONEncoder().encode(entry) let decoded = try JSONDecoder().decode(ETagCacheEntry.self, from: data) #expect(decoded.etag == "abc123") #expect(decoded.lastModified == "2024-01-01") } } // MARK: - SyncOperation Codable Tests struct SyncOperationCodableTests { @Test("SyncOperation encodes and decodes correctly") func encodeDecode() throws { let operation = SyncOperation.appRefresh let data = try JSONEncoder().encode(operation) let decoded = try JSONDecoder().decode(SyncOperation.self, from: data) #expect(decoded == .appRefresh) } @Test("All SyncOperation values encode and decode correctly") func allOperationsEncodeDecode() throws { let operations: [SyncOperation] = [ .appRefresh, .darkWebScan, .spamDatabaseUpdate, .pushNotificationSync, .manual ] for op in operations { let data = try JSONEncoder().encode(op) let decoded = try JSONDecoder().decode(SyncOperation.self, from: data) #expect(decoded == op) } } } // MARK: - SyncState Codable Tests struct SyncStateCodableTests { @Test("SyncState encodes and decodes correctly") func encodeDecode() throws { let state = SyncState.syncing let data = try JSONEncoder().encode(state) let decoded = try JSONDecoder().decode(SyncState.self, from: data) #expect(decoded == .syncing) } @Test("All SyncState values encode and decode correctly") func allStatesEncodeDecode() throws { let states: [SyncState] = [.idle, .syncing, .completed, .failed, .offline] for state in states { let data = try JSONEncoder().encode(state) let decoded = try JSONDecoder().decode(SyncState.self, from: data) #expect(decoded == state) } } } // MARK: - SyncProgress Tests struct SyncProgressTests { @Test("SyncProgress is Equatable on stage") func progressStageEquatable() { #expect(SyncProgressStage.fetching(label: "alerts") == SyncProgressStage.fetching(label: "alerts")) #expect(SyncProgressStage.fetching(label: "alerts") != SyncProgressStage.fetching(label: "exposures")) #expect(SyncProgressStage.processing == SyncProgressStage.processing) #expect(SyncProgressStage.completed == SyncProgressStage.completed) #expect(SyncProgressStage.processing != SyncProgressStage.saving) } } // MARK: - Background Fetch Timing Tests struct BackgroundFetchTimingTests { @Test("App refresh interval meets 15-minute minimum") func appRefreshMeetsMinimum() { let scheduler = BackgroundTaskScheduler() #expect(scheduler.minimumRefreshInterval >= 15 * 60) } @Test("Low power mode doubles the refresh interval") func lowPowerDoublesInterval() { let scheduler = BackgroundTaskScheduler() #expect(scheduler.lowPowerRefreshInterval == scheduler.minimumRefreshInterval * 2) } @Test("Dark web scan interval in low power mode is doubled") func lowPowerDarkWebDoublesInterval() { let scheduler = BackgroundTaskScheduler() #expect(scheduler.lowPowerDarkWebScanInterval == scheduler.darkWebScanInterval * 2) } @Test("Spam update interval in low power mode is doubled") func lowPowerSpamDoublesInterval() { let scheduler = BackgroundTaskScheduler() #expect(scheduler.lowPowerSpamUpdateInterval == scheduler.spamUpdateInterval * 2) } } // MARK: - Delta Sync Savings Tests struct DeltaSyncSavingsTests { @Test("Delta sync savings percent is 0 when no savings") func noSavings() { var status = SyncStatus() status.totalBytesTransferred = 1000 status.deltaSyncSavings = 0 #expect(status.deltaSyncSavingsPercent == 0.0) } @Test("Delta sync savings percent is 100 when all data was cached") func allCached() { var status = SyncStatus() status.totalBytesTransferred = 0 status.deltaSyncSavings = 1000 #expect(status.deltaSyncSavingsPercent == 100.0) } @Test("Delta sync savings percent is 75 when 75% was saved") func seventyFivePercentSaved() { var status = SyncStatus() status.totalBytesTransferred = 250 status.deltaSyncSavings = 750 // 750 / (250 + 750) * 100 = 75% #expect(status.deltaSyncSavingsPercent == 75.0) } } // MARK: - DeltaSyncResult Tests struct DeltaSyncResultTests { @Test("DeltaSyncResult deltaSavingsRatio is 0 when no data") func zeroRatio() { let result = DeltaSyncResult( alertsChanged: false, exposuresChanged: false, watchlistChanged: false, bytesTransferred: 0, deltaSavings: 0, newAlerts: [], newExposures: [] ) #expect(result.deltaSavingsRatio == 0) } @Test("DeltaSyncResult deltaSavingsRatio calculates correctly") func ratioCalculation() { let result = DeltaSyncResult( alertsChanged: true, exposuresChanged: false, watchlistChanged: false, bytesTransferred: 250, deltaSavings: 750, newAlerts: [], newExposures: [] ) // 750 / (250 + 750) = 0.75 #expect(result.deltaSavingsRatio == 0.75) } @Test("DeltaSyncResult deltaSavingsRatio is 1.0 when nothing transferred") func allSaved() { let result = DeltaSyncResult( alertsChanged: false, exposuresChanged: false, watchlistChanged: false, bytesTransferred: 0, deltaSavings: 1000, newAlerts: [], newExposures: [] ) #expect(result.deltaSavingsRatio == 1.0) } } // MARK: - BatteryUsageMetrics Tests struct BatteryUsageMetricsTests { @Test("BatteryUsageMetrics defaults are correct") func defaults() { let metrics = BatteryUsageMetrics() #expect(metrics.totalSyncTime == 0) #expect(metrics.syncCount == 0) #expect(metrics.totalBytesTransferred == 0) #expect(metrics.estimatedBatteryDrain == 0) #expect(metrics.averageSyncDuration == 0) #expect(metrics.batteryDrainPerSync == 0) } @Test("BatteryUsageMetrics records sync correctly") func recordSync() { var metrics = BatteryUsageMetrics() metrics.recordSync(duration: 2.5, bytesTransferred: 10240) #expect(metrics.syncCount == 1) #expect(metrics.totalSyncTime == 2.5) #expect(metrics.totalBytesTransferred == 10240) #expect(metrics.averageSyncDuration == 2.5) #expect(metrics.estimatedBatteryDrain > 0) } @Test("BatteryUsageMetrics accumulates across multiple syncs") func accumulate() { var metrics = BatteryUsageMetrics() metrics.recordSync(duration: 2.0, bytesTransferred: 5000) metrics.recordSync(duration: 3.0, bytesTransferred: 10000) #expect(metrics.syncCount == 2) #expect(metrics.totalSyncTime == 5.0) #expect(metrics.totalBytesTransferred == 15000) #expect(metrics.averageSyncDuration == 2.5) } @Test("BatteryUsageMetrics calculates drain per sync") func batteryDrainPerSync() { var metrics = BatteryUsageMetrics() metrics.recordSync(duration: 2.0, bytesTransferred: 10240) metrics.recordSync(duration: 3.0, bytesTransferred: 20480) #expect(metrics.batteryDrainPerSync > 0) #expect(metrics.batteryDrainPerSync == metrics.estimatedBatteryDrain / 2.0) } @Test("BatteryUsageMetrics reset clears all values") func reset() { var metrics = BatteryUsageMetrics() metrics.recordSync(duration: 2.0, bytesTransferred: 10240) metrics.reset() #expect(metrics.syncCount == 0) #expect(metrics.totalSyncTime == 0) #expect(metrics.totalBytesTransferred == 0) #expect(metrics.estimatedBatteryDrain == 0) } @Test("BatteryUsageMetrics is Codable") func codable() throws { var metrics = BatteryUsageMetrics() metrics.recordSync(duration: 2.5, bytesTransferred: 10240) let data = try JSONEncoder().encode(metrics) let decoded = try JSONDecoder().decode(BatteryUsageMetrics.self, from: data) #expect(decoded.syncCount == 1) #expect(decoded.totalSyncTime == 2.5) #expect(decoded.totalBytesTransferred == 10240) } } // MARK: - SyncStatus Extended Tests struct SyncStatusExtendedTests { @Test("SyncStatus totalSyncCount starts at 0") func defaultSyncCount() { let status = SyncStatus() #expect(status.totalSyncCount == 0) } @Test("SyncStatus syncSummary shows never when no syncs") func syncSummaryNoSyncs() { let status = SyncStatus() #expect(status.syncSummary.contains("No syncs")) } @Test("SyncStatus syncSummary shows count and stats") func syncSummaryWithStats() { var status = SyncStatus() status.totalSyncCount = 5 status.totalBytesTransferred = 2048 status.deltaSyncSavings = 1024 let summary = status.syncSummary #expect(summary.contains("5 syncs")) #expect(summary.contains("33%")) } @Test("SyncStatus equality includes totalSyncCount") func equalityIncludesSyncCount() { var status1 = SyncStatus() var status2 = SyncStatus() status1.totalSyncCount = 5 status2.totalSyncCount = 10 #expect(status1 != status2) } } // MARK: - SyncStatusManager Extended Tests @MainActor struct SyncStatusManagerExtendedTests { @Test("SyncStatusManager completeSync increments totalSyncCount") func incrementSyncCount() { let manager = SyncStatusManager(defaults: UserDefaults(suiteName: UUID().uuidString)!) #expect(manager.status.totalSyncCount == 0) manager.completeSync(bytesTransferred: 100, deltaSavings: 50) #expect(manager.status.totalSyncCount == 1) manager.completeSync(bytesTransferred: 200, deltaSavings: 100) #expect(manager.status.totalSyncCount == 2) } @Test("SyncStatusManager persists totalSyncCount") func persistSyncCount() { let defaults = UserDefaults(suiteName: UUID().uuidString)! let manager1 = SyncStatusManager(defaults: defaults) manager1.completeSync(bytesTransferred: 100, deltaSavings: 50) manager1.completeSync(bytesTransferred: 200, deltaSavings: 100) let manager2 = SyncStatusManager(defaults: defaults) #expect(manager2.status.totalSyncCount == 2) } } // MARK: - BackgroundTaskScheduler Extended Tests struct BackgroundTaskSchedulerExtendedTests { @Test("BackgroundTaskScheduler rescheduleAllTasks does not crash") func rescheduleAllTasks() { let scheduler = BackgroundTaskScheduler() // Should not throw scheduler.rescheduleAllTasks() } @Test("BackgroundTaskScheduler rescheduleAllTasks skips when task is running") func rescheduleSkipsWhenRunning() { let scheduler = BackgroundTaskScheduler() // Initially no task running, reschedule should work scheduler.rescheduleAllTasks() #expect(scheduler.currentlyHasRunningTask == false) } } // MARK: - BackgroundSyncService Extended Tests struct BackgroundSyncServiceExtendedTests { @Test("BackgroundSyncService battery metrics start at zero") func batteryMetricsStartAtZero() { let metrics = BackgroundSyncService.shared.currentBatteryMetrics #expect(metrics.syncCount == 0) #expect(metrics.totalSyncTime == 0) #expect(metrics.estimatedBatteryDrain == 0) } @Test("BackgroundSyncService resetBatteryMetrics clears values") func resetBatteryMetrics() { BackgroundSyncService.shared.resetBatteryMetrics() let metrics = BackgroundSyncService.shared.currentBatteryMetrics #expect(metrics.syncCount == 0) #expect(metrics.totalSyncTime == 0) #expect(metrics.estimatedBatteryDrain == 0) } } // MARK: - ConditionalResponseMetadata Tests struct ConditionalResponseMetadataTests { @Test("ConditionalResponseMetadata defaults are correct") func defaults() { let metadata = ConditionalResponseMetadata( etag: nil, lastModified: nil, notModified: false ) #expect(metadata.etag == nil) #expect(metadata.lastModified == nil) #expect(metadata.notModified == false) } @Test("ConditionalResponseMetadata stores ETag and lastModified") func storesHeaders() { let metadata = ConditionalResponseMetadata( etag: "\"abc123\"", lastModified: "Wed, 21 Oct 2015 07:28:00 GMT", notModified: false ) #expect(metadata.etag == "\"abc123\"") #expect(metadata.lastModified == "Wed, 21 Oct 2015 07:28:00 GMT") #expect(metadata.notModified == false) } @Test("ConditionalResponseMetadata marks 304 response") func notModified() { let metadata = ConditionalResponseMetadata( etag: "\"abc123\"", lastModified: nil, notModified: true ) #expect(metadata.notModified == true) } }