general: test redux
This commit is contained in:
135
GazeTests/Services/EnforceModeServiceTests.swift
Normal file
135
GazeTests/Services/EnforceModeServiceTests.swift
Normal file
@@ -0,0 +1,135 @@
|
||||
//
|
||||
// EnforceModeServiceTests.swift
|
||||
// GazeTests
|
||||
//
|
||||
// Unit tests for EnforceModeService.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import Gaze
|
||||
|
||||
@MainActor
|
||||
final class EnforceModeServiceTests: XCTestCase {
|
||||
|
||||
var service: EnforceModeService!
|
||||
|
||||
override func setUp() async throws {
|
||||
service = EnforceModeService.shared
|
||||
}
|
||||
|
||||
override func tearDown() async throws {
|
||||
service.disableEnforceMode()
|
||||
service = nil
|
||||
}
|
||||
|
||||
// MARK: - Initialization Tests
|
||||
|
||||
func testServiceInitialization() {
|
||||
XCTAssertNotNil(service)
|
||||
}
|
||||
|
||||
func testInitialState() {
|
||||
XCTAssertFalse(service.isEnforceModeEnabled)
|
||||
XCTAssertFalse(service.isCameraActive)
|
||||
XCTAssertFalse(service.userCompliedWithBreak)
|
||||
}
|
||||
|
||||
// MARK: - Enable/Disable Tests
|
||||
|
||||
func testEnableEnforceMode() async {
|
||||
await service.enableEnforceMode()
|
||||
|
||||
// May or may not be enabled depending on camera permissions
|
||||
// Just verify the method doesn't crash
|
||||
XCTAssertNotNil(service)
|
||||
}
|
||||
|
||||
func testDisableEnforceMode() {
|
||||
service.disableEnforceMode()
|
||||
|
||||
XCTAssertFalse(service.isEnforceModeEnabled)
|
||||
XCTAssertFalse(service.isCameraActive)
|
||||
}
|
||||
|
||||
func testEnableDisableCycle() async {
|
||||
await service.enableEnforceMode()
|
||||
service.disableEnforceMode()
|
||||
|
||||
XCTAssertFalse(service.isEnforceModeEnabled)
|
||||
}
|
||||
|
||||
// MARK: - Timer Engine Integration Tests
|
||||
|
||||
func testSetTimerEngine() {
|
||||
let testEnv = TestEnvironment()
|
||||
let timerEngine = testEnv.container.timerEngine
|
||||
|
||||
service.setTimerEngine(timerEngine)
|
||||
|
||||
// Should not crash
|
||||
XCTAssertNotNil(service)
|
||||
}
|
||||
|
||||
// MARK: - Should Enforce Break Tests
|
||||
|
||||
func testShouldEnforceBreakWhenDisabled() {
|
||||
service.disableEnforceMode()
|
||||
|
||||
let shouldEnforce = service.shouldEnforceBreak(for: .builtIn(.lookAway))
|
||||
XCTAssertFalse(shouldEnforce)
|
||||
}
|
||||
|
||||
// MARK: - Camera Tests
|
||||
|
||||
func testStopCamera() {
|
||||
service.stopCamera()
|
||||
|
||||
XCTAssertFalse(service.isCameraActive)
|
||||
}
|
||||
|
||||
// MARK: - Compliance Tests
|
||||
|
||||
func testCheckUserCompliance() {
|
||||
service.checkUserCompliance()
|
||||
|
||||
// Should not crash
|
||||
XCTAssertNotNil(service)
|
||||
}
|
||||
|
||||
func testHandleReminderDismissed() {
|
||||
service.handleReminderDismissed()
|
||||
|
||||
// Should not crash
|
||||
XCTAssertNotNil(service)
|
||||
}
|
||||
|
||||
// MARK: - Test Mode Tests
|
||||
|
||||
func testStartTestMode() async {
|
||||
await service.startTestMode()
|
||||
|
||||
XCTAssertTrue(service.isTestMode)
|
||||
}
|
||||
|
||||
func testStopTestMode() {
|
||||
service.stopTestMode()
|
||||
|
||||
XCTAssertFalse(service.isTestMode)
|
||||
}
|
||||
|
||||
func testTestModeCycle() async {
|
||||
await service.startTestMode()
|
||||
XCTAssertTrue(service.isTestMode)
|
||||
|
||||
service.stopTestMode()
|
||||
XCTAssertFalse(service.isTestMode)
|
||||
}
|
||||
|
||||
// MARK: - Protocol Conformance Tests
|
||||
|
||||
func testConformsToEnforceModeProviding() {
|
||||
let providing: EnforceModeProviding = service
|
||||
XCTAssertNotNil(providing)
|
||||
XCTAssertFalse(providing.isEnforceModeEnabled)
|
||||
}
|
||||
}
|
||||
68
GazeTests/Services/FullscreenDetectionServiceTests.swift
Normal file
68
GazeTests/Services/FullscreenDetectionServiceTests.swift
Normal file
@@ -0,0 +1,68 @@
|
||||
//
|
||||
// FullscreenDetectionServiceTests.swift
|
||||
// GazeTests
|
||||
//
|
||||
// Unit tests for FullscreenDetectionService.
|
||||
//
|
||||
|
||||
import Combine
|
||||
import XCTest
|
||||
@testable import Gaze
|
||||
|
||||
@MainActor
|
||||
final class FullscreenDetectionServiceTests: XCTestCase {
|
||||
|
||||
var service: FullscreenDetectionService!
|
||||
var cancellables: Set<AnyCancellable>!
|
||||
|
||||
override func setUp() async throws {
|
||||
service = FullscreenDetectionService()
|
||||
cancellables = []
|
||||
}
|
||||
|
||||
override func tearDown() async throws {
|
||||
cancellables = nil
|
||||
service = nil
|
||||
}
|
||||
|
||||
// MARK: - Initialization Tests
|
||||
|
||||
func testServiceInitialization() {
|
||||
XCTAssertNotNil(service)
|
||||
}
|
||||
|
||||
func testInitialFullscreenState() {
|
||||
// Initially should not be in fullscreen (unless actually in fullscreen)
|
||||
XCTAssertNotNil(service.isFullscreenActive)
|
||||
}
|
||||
|
||||
// MARK: - Publisher Tests
|
||||
|
||||
func testFullscreenStatePublisher() async throws {
|
||||
let expectation = XCTestExpectation(description: "Fullscreen state published")
|
||||
|
||||
service.$isFullscreenActive
|
||||
.sink { isFullscreen in
|
||||
expectation.fulfill()
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
await fulfillment(of: [expectation], timeout: 0.1)
|
||||
}
|
||||
|
||||
// MARK: - Force Update Tests
|
||||
|
||||
func testForceUpdate() {
|
||||
// Should not crash
|
||||
service.forceUpdate()
|
||||
XCTAssertNotNil(service.isFullscreenActive)
|
||||
}
|
||||
|
||||
// MARK: - Protocol Conformance Tests
|
||||
|
||||
func testConformsToFullscreenDetectionProviding() {
|
||||
let providing: FullscreenDetectionProviding = service
|
||||
XCTAssertNotNil(providing)
|
||||
XCTAssertNotNil(providing.isFullscreenActive)
|
||||
}
|
||||
}
|
||||
89
GazeTests/Services/IdleMonitoringServiceTests.swift
Normal file
89
GazeTests/Services/IdleMonitoringServiceTests.swift
Normal file
@@ -0,0 +1,89 @@
|
||||
//
|
||||
// IdleMonitoringServiceTests.swift
|
||||
// GazeTests
|
||||
//
|
||||
// Unit tests for IdleMonitoringService.
|
||||
//
|
||||
|
||||
import Combine
|
||||
import XCTest
|
||||
@testable import Gaze
|
||||
|
||||
@MainActor
|
||||
final class IdleMonitoringServiceTests: XCTestCase {
|
||||
|
||||
var service: IdleMonitoringService!
|
||||
var cancellables: Set<AnyCancellable>!
|
||||
|
||||
override func setUp() async throws {
|
||||
service = IdleMonitoringService(idleThresholdMinutes: 5)
|
||||
cancellables = []
|
||||
}
|
||||
|
||||
override func tearDown() async throws {
|
||||
cancellables = nil
|
||||
service = nil
|
||||
}
|
||||
|
||||
// MARK: - Initialization Tests
|
||||
|
||||
func testServiceInitialization() {
|
||||
XCTAssertNotNil(service)
|
||||
}
|
||||
|
||||
func testInitialIdleState() {
|
||||
// Initially should not be idle
|
||||
XCTAssertFalse(service.isIdle)
|
||||
}
|
||||
|
||||
func testInitializationWithCustomThreshold() {
|
||||
let customService = IdleMonitoringService(idleThresholdMinutes: 10)
|
||||
XCTAssertNotNil(customService)
|
||||
}
|
||||
|
||||
// MARK: - Threshold Tests
|
||||
|
||||
func testUpdateThreshold() {
|
||||
service.updateThreshold(minutes: 15)
|
||||
|
||||
// Should not crash
|
||||
XCTAssertNotNil(service)
|
||||
}
|
||||
|
||||
func testUpdateThresholdMultipleTimes() {
|
||||
service.updateThreshold(minutes: 5)
|
||||
service.updateThreshold(minutes: 10)
|
||||
service.updateThreshold(minutes: 3)
|
||||
|
||||
XCTAssertNotNil(service)
|
||||
}
|
||||
|
||||
// MARK: - Publisher Tests
|
||||
|
||||
func testIdleStatePublisher() async throws {
|
||||
let expectation = XCTestExpectation(description: "Idle state published")
|
||||
|
||||
service.$isIdle
|
||||
.sink { isIdle in
|
||||
expectation.fulfill()
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
await fulfillment(of: [expectation], timeout: 0.1)
|
||||
}
|
||||
|
||||
// MARK: - Force Update Tests
|
||||
|
||||
func testForceUpdate() {
|
||||
service.forceUpdate()
|
||||
XCTAssertNotNil(service.isIdle)
|
||||
}
|
||||
|
||||
// MARK: - Protocol Conformance Tests
|
||||
|
||||
func testConformsToIdleMonitoringProviding() {
|
||||
let providing: IdleMonitoringProviding = service
|
||||
XCTAssertNotNil(providing)
|
||||
XCTAssertNotNil(providing.isIdle)
|
||||
}
|
||||
}
|
||||
61
GazeTests/Services/LoggingManagerTests.swift
Normal file
61
GazeTests/Services/LoggingManagerTests.swift
Normal file
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// LoggingManagerTests.swift
|
||||
// GazeTests
|
||||
//
|
||||
// Unit tests for LoggingManager.
|
||||
//
|
||||
|
||||
import os.log
|
||||
import XCTest
|
||||
@testable import Gaze
|
||||
|
||||
final class LoggingManagerTests: XCTestCase {
|
||||
|
||||
var loggingManager: LoggingManager!
|
||||
|
||||
override func setUp() {
|
||||
loggingManager = LoggingManager.shared
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
loggingManager = nil
|
||||
}
|
||||
|
||||
// MARK: - Initialization Tests
|
||||
|
||||
func testLoggingManagerInitialization() {
|
||||
XCTAssertNotNil(loggingManager)
|
||||
}
|
||||
|
||||
func testLoggersExist() {
|
||||
XCTAssertNotNil(loggingManager.appLogger)
|
||||
XCTAssertNotNil(loggingManager.timerLogger)
|
||||
XCTAssertNotNil(loggingManager.systemLogger)
|
||||
}
|
||||
|
||||
// MARK: - Configuration Tests
|
||||
|
||||
func testConfigureLogging() {
|
||||
// Should not crash
|
||||
loggingManager.configureLogging()
|
||||
XCTAssertNotNil(loggingManager)
|
||||
}
|
||||
|
||||
// MARK: - Logger Usage Tests
|
||||
|
||||
func testAppLoggerLogging() {
|
||||
// Should not crash
|
||||
loggingManager.appLogger.info("Test app log")
|
||||
XCTAssertNotNil(loggingManager.appLogger)
|
||||
}
|
||||
|
||||
func testTimerLoggerLogging() {
|
||||
loggingManager.timerLogger.info("Test timer log")
|
||||
XCTAssertNotNil(loggingManager.timerLogger)
|
||||
}
|
||||
|
||||
func testSystemLoggerLogging() {
|
||||
loggingManager.systemLogger.info("Test system log")
|
||||
XCTAssertNotNil(loggingManager.systemLogger)
|
||||
}
|
||||
}
|
||||
187
GazeTests/Services/SettingsManagerTests.swift
Normal file
187
GazeTests/Services/SettingsManagerTests.swift
Normal file
@@ -0,0 +1,187 @@
|
||||
//
|
||||
// SettingsManagerTests.swift
|
||||
// GazeTests
|
||||
//
|
||||
// Unit tests for SettingsManager service.
|
||||
//
|
||||
|
||||
import Combine
|
||||
import XCTest
|
||||
@testable import Gaze
|
||||
|
||||
@MainActor
|
||||
final class SettingsManagerTests: XCTestCase {
|
||||
|
||||
var settingsManager: SettingsManager!
|
||||
var cancellables: Set<AnyCancellable>!
|
||||
|
||||
override func setUp() async throws {
|
||||
settingsManager = SettingsManager.shared
|
||||
cancellables = []
|
||||
|
||||
// Reset to defaults for testing
|
||||
settingsManager.resetToDefaults()
|
||||
}
|
||||
|
||||
override func tearDown() async throws {
|
||||
cancellables = nil
|
||||
settingsManager = nil
|
||||
}
|
||||
|
||||
// MARK: - Initialization Tests
|
||||
|
||||
func testSettingsManagerInitialization() {
|
||||
XCTAssertNotNil(settingsManager)
|
||||
XCTAssertNotNil(settingsManager.settings)
|
||||
}
|
||||
|
||||
func testDefaultSettingsValues() {
|
||||
let defaults = AppSettings.defaults
|
||||
|
||||
XCTAssertTrue(defaults.lookAwayTimer.enabled)
|
||||
XCTAssertTrue(defaults.blinkTimer.enabled)
|
||||
XCTAssertTrue(defaults.postureTimer.enabled)
|
||||
XCTAssertFalse(defaults.hasCompletedOnboarding)
|
||||
}
|
||||
|
||||
// MARK: - Timer Configuration Tests
|
||||
|
||||
func testGetTimerConfiguration() {
|
||||
let lookAwayConfig = settingsManager.timerConfiguration(for: .lookAway)
|
||||
XCTAssertNotNil(lookAwayConfig)
|
||||
XCTAssertTrue(lookAwayConfig.enabled)
|
||||
}
|
||||
|
||||
func testUpdateTimerConfiguration() {
|
||||
var config = settingsManager.timerConfiguration(for: .lookAway)
|
||||
config.intervalSeconds = 1500
|
||||
config.enabled = false
|
||||
|
||||
settingsManager.updateTimerConfiguration(for: .lookAway, configuration: config)
|
||||
|
||||
let updated = settingsManager.timerConfiguration(for: .lookAway)
|
||||
XCTAssertEqual(updated.intervalSeconds, 1500)
|
||||
XCTAssertFalse(updated.enabled)
|
||||
}
|
||||
|
||||
func testAllTimerConfigurations() {
|
||||
let allConfigs = settingsManager.allTimerConfigurations()
|
||||
|
||||
XCTAssertEqual(allConfigs.count, 3)
|
||||
XCTAssertNotNil(allConfigs[.lookAway])
|
||||
XCTAssertNotNil(allConfigs[.blink])
|
||||
XCTAssertNotNil(allConfigs[.posture])
|
||||
}
|
||||
|
||||
func testUpdateMultipleTimerConfigurations() {
|
||||
var lookAway = settingsManager.timerConfiguration(for: .lookAway)
|
||||
lookAway.intervalSeconds = 1000
|
||||
settingsManager.updateTimerConfiguration(for: .lookAway, configuration: lookAway)
|
||||
|
||||
var blink = settingsManager.timerConfiguration(for: .blink)
|
||||
blink.intervalSeconds = 250
|
||||
settingsManager.updateTimerConfiguration(for: .blink, configuration: blink)
|
||||
|
||||
XCTAssertEqual(settingsManager.timerConfiguration(for: .lookAway).intervalSeconds, 1000)
|
||||
XCTAssertEqual(settingsManager.timerConfiguration(for: .blink).intervalSeconds, 250)
|
||||
}
|
||||
|
||||
// MARK: - Settings Publisher Tests
|
||||
|
||||
func testSettingsPublisherEmitsChanges() async throws {
|
||||
let expectation = XCTestExpectation(description: "Settings changed")
|
||||
var receivedSettings: AppSettings?
|
||||
|
||||
settingsManager.$settings
|
||||
.dropFirst() // Skip initial value
|
||||
.sink { settings in
|
||||
receivedSettings = settings
|
||||
expectation.fulfill()
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
// Trigger change
|
||||
settingsManager.settings.playSounds = !settingsManager.settings.playSounds
|
||||
|
||||
await fulfillment(of: [expectation], timeout: 1.0)
|
||||
XCTAssertNotNil(receivedSettings)
|
||||
}
|
||||
|
||||
// MARK: - Save/Load Tests
|
||||
|
||||
func testSave() {
|
||||
settingsManager.settings.playSounds = false
|
||||
settingsManager.save()
|
||||
|
||||
// Save is debounced, so just verify it doesn't crash
|
||||
XCTAssertFalse(settingsManager.settings.playSounds)
|
||||
}
|
||||
|
||||
func testSaveImmediately() {
|
||||
settingsManager.settings.launchAtLogin = true
|
||||
settingsManager.saveImmediately()
|
||||
|
||||
// Verify the setting persisted
|
||||
XCTAssertTrue(settingsManager.settings.launchAtLogin)
|
||||
}
|
||||
|
||||
func testLoad() {
|
||||
// Load should restore settings from UserDefaults
|
||||
settingsManager.load()
|
||||
XCTAssertNotNil(settingsManager.settings)
|
||||
}
|
||||
|
||||
// MARK: - Reset Tests
|
||||
|
||||
func testResetToDefaults() {
|
||||
// Modify settings
|
||||
settingsManager.settings.playSounds = false
|
||||
settingsManager.settings.launchAtLogin = true
|
||||
var config = settingsManager.timerConfiguration(for: .lookAway)
|
||||
config.intervalSeconds = 5000
|
||||
settingsManager.updateTimerConfiguration(for: .lookAway, configuration: config)
|
||||
|
||||
// Reset
|
||||
settingsManager.resetToDefaults()
|
||||
|
||||
// Verify reset to defaults
|
||||
let defaults = AppSettings.defaults
|
||||
XCTAssertEqual(settingsManager.settings.playSounds, defaults.playSounds)
|
||||
XCTAssertEqual(settingsManager.settings.launchAtLogin, defaults.launchAtLogin)
|
||||
}
|
||||
|
||||
// MARK: - Onboarding Tests
|
||||
|
||||
func testOnboardingCompletion() {
|
||||
XCTAssertFalse(settingsManager.settings.hasCompletedOnboarding)
|
||||
|
||||
settingsManager.settings.hasCompletedOnboarding = true
|
||||
XCTAssertTrue(settingsManager.settings.hasCompletedOnboarding)
|
||||
}
|
||||
|
||||
// MARK: - General Settings Tests
|
||||
|
||||
func testPlaySoundsToggle() {
|
||||
let initial = settingsManager.settings.playSounds
|
||||
settingsManager.settings.playSounds = !initial
|
||||
XCTAssertNotEqual(settingsManager.settings.playSounds, initial)
|
||||
}
|
||||
|
||||
func testLaunchAtLoginToggle() {
|
||||
let initial = settingsManager.settings.launchAtLogin
|
||||
settingsManager.settings.launchAtLogin = !initial
|
||||
XCTAssertNotEqual(settingsManager.settings.launchAtLogin, initial)
|
||||
}
|
||||
|
||||
// MARK: - Smart Mode Settings Tests
|
||||
|
||||
func testSmartModeSettings() {
|
||||
settingsManager.settings.smartMode.autoPauseOnFullscreen = true
|
||||
settingsManager.settings.smartMode.autoPauseOnIdle = true
|
||||
settingsManager.settings.smartMode.idleThresholdMinutes = 10
|
||||
|
||||
XCTAssertTrue(settingsManager.settings.smartMode.autoPauseOnFullscreen)
|
||||
XCTAssertTrue(settingsManager.settings.smartMode.autoPauseOnIdle)
|
||||
XCTAssertEqual(settingsManager.settings.smartMode.idleThresholdMinutes, 10)
|
||||
}
|
||||
}
|
||||
302
GazeTests/Services/TimerEngineTests.swift
Normal file
302
GazeTests/Services/TimerEngineTests.swift
Normal file
@@ -0,0 +1,302 @@
|
||||
//
|
||||
// TimerEngineTests.swift
|
||||
// GazeTests
|
||||
//
|
||||
// Unit tests for TimerEngine service.
|
||||
//
|
||||
|
||||
import Combine
|
||||
import XCTest
|
||||
@testable import Gaze
|
||||
|
||||
@MainActor
|
||||
final class TimerEngineTests: XCTestCase {
|
||||
|
||||
var testEnv: TestEnvironment!
|
||||
var timerEngine: TimerEngine!
|
||||
var cancellables: Set<AnyCancellable>!
|
||||
|
||||
override func setUp() async throws {
|
||||
testEnv = TestEnvironment(settings: .defaults)
|
||||
timerEngine = testEnv.container.timerEngine
|
||||
cancellables = []
|
||||
}
|
||||
|
||||
override func tearDown() async throws {
|
||||
timerEngine?.stop()
|
||||
cancellables = nil
|
||||
timerEngine = nil
|
||||
testEnv = nil
|
||||
}
|
||||
|
||||
// MARK: - Initialization Tests
|
||||
|
||||
func testTimerEngineInitialization() {
|
||||
XCTAssertNotNil(timerEngine)
|
||||
XCTAssertEqual(timerEngine.timerStates.count, 0)
|
||||
XCTAssertNil(timerEngine.activeReminder)
|
||||
}
|
||||
|
||||
func testTimerEngineWithCustomTimeProvider() {
|
||||
let timeProvider = MockTimeProvider()
|
||||
let engine = TimerEngine(
|
||||
settingsManager: testEnv.settingsManager,
|
||||
timeProvider: timeProvider
|
||||
)
|
||||
|
||||
XCTAssertNotNil(engine)
|
||||
}
|
||||
|
||||
// MARK: - Start/Stop Tests
|
||||
|
||||
func testStartTimers() {
|
||||
timerEngine.start()
|
||||
|
||||
// Should create timer states for enabled timers
|
||||
XCTAssertGreaterThan(timerEngine.timerStates.count, 0)
|
||||
}
|
||||
|
||||
func testStopTimers() {
|
||||
timerEngine.start()
|
||||
let initialCount = timerEngine.timerStates.count
|
||||
XCTAssertGreaterThan(initialCount, 0)
|
||||
|
||||
timerEngine.stop()
|
||||
|
||||
// Timers should be cleared
|
||||
XCTAssertEqual(timerEngine.timerStates.count, 0)
|
||||
}
|
||||
|
||||
func testRestartTimers() {
|
||||
timerEngine.start()
|
||||
let firstCount = timerEngine.timerStates.count
|
||||
|
||||
timerEngine.stop()
|
||||
XCTAssertEqual(timerEngine.timerStates.count, 0)
|
||||
|
||||
timerEngine.start()
|
||||
let secondCount = timerEngine.timerStates.count
|
||||
|
||||
XCTAssertEqual(firstCount, secondCount)
|
||||
}
|
||||
|
||||
// MARK: - Pause/Resume Tests
|
||||
|
||||
func testPauseAllTimers() {
|
||||
timerEngine.start()
|
||||
timerEngine.pause()
|
||||
|
||||
for (_, state) in timerEngine.timerStates {
|
||||
XCTAssertTrue(state.isPaused)
|
||||
}
|
||||
}
|
||||
|
||||
func testResumeAllTimers() {
|
||||
timerEngine.start()
|
||||
timerEngine.pause()
|
||||
timerEngine.resume()
|
||||
|
||||
for (_, state) in timerEngine.timerStates {
|
||||
XCTAssertFalse(state.isPaused)
|
||||
}
|
||||
}
|
||||
|
||||
func testPauseSpecificTimer() {
|
||||
timerEngine.start()
|
||||
|
||||
guard let firstTimer = timerEngine.timerStates.keys.first else {
|
||||
XCTFail("No timers available")
|
||||
return
|
||||
}
|
||||
|
||||
timerEngine.pauseTimer(identifier: firstTimer)
|
||||
|
||||
let state = timerEngine.timerStates[firstTimer]
|
||||
XCTAssertTrue(state?.isPaused ?? false)
|
||||
}
|
||||
|
||||
func testResumeSpecificTimer() {
|
||||
timerEngine.start()
|
||||
|
||||
guard let firstTimer = timerEngine.timerStates.keys.first else {
|
||||
XCTFail("No timers available")
|
||||
return
|
||||
}
|
||||
|
||||
timerEngine.pauseTimer(identifier: firstTimer)
|
||||
XCTAssertTrue(timerEngine.isTimerPaused(firstTimer))
|
||||
|
||||
timerEngine.resumeTimer(identifier: firstTimer)
|
||||
XCTAssertFalse(timerEngine.isTimerPaused(firstTimer))
|
||||
}
|
||||
|
||||
// MARK: - Skip Tests
|
||||
|
||||
func testSkipNext() {
|
||||
timerEngine.start()
|
||||
|
||||
guard let firstTimer = timerEngine.timerStates.keys.first else {
|
||||
XCTFail("No timers available")
|
||||
return
|
||||
}
|
||||
|
||||
timerEngine.skipNext(identifier: firstTimer)
|
||||
|
||||
// Timer should be reset
|
||||
XCTAssertNotNil(timerEngine.timerStates[firstTimer])
|
||||
}
|
||||
|
||||
// MARK: - Reminder Tests
|
||||
|
||||
func testTriggerReminder() async throws {
|
||||
timerEngine.start()
|
||||
|
||||
guard let firstTimer = timerEngine.timerStates.keys.first else {
|
||||
XCTFail("No timers available")
|
||||
return
|
||||
}
|
||||
|
||||
timerEngine.triggerReminder(for: firstTimer)
|
||||
|
||||
// Give time for async operations
|
||||
try await Task.sleep(nanoseconds: 50_000_000)
|
||||
|
||||
XCTAssertNotNil(timerEngine.activeReminder)
|
||||
}
|
||||
|
||||
func testDismissReminder() {
|
||||
timerEngine.start()
|
||||
|
||||
guard let firstTimer = timerEngine.timerStates.keys.first else {
|
||||
XCTFail("No timers available")
|
||||
return
|
||||
}
|
||||
|
||||
timerEngine.triggerReminder(for: firstTimer)
|
||||
XCTAssertNotNil(timerEngine.activeReminder)
|
||||
|
||||
timerEngine.dismissReminder()
|
||||
XCTAssertNil(timerEngine.activeReminder)
|
||||
}
|
||||
|
||||
// MARK: - Time Remaining Tests
|
||||
|
||||
func testGetTimeRemaining() {
|
||||
timerEngine.start()
|
||||
|
||||
guard let firstTimer = timerEngine.timerStates.keys.first else {
|
||||
XCTFail("No timers available")
|
||||
return
|
||||
}
|
||||
|
||||
let remaining = timerEngine.getTimeRemaining(for: firstTimer)
|
||||
XCTAssertGreaterThan(remaining, 0)
|
||||
}
|
||||
|
||||
func testGetFormattedTimeRemaining() {
|
||||
timerEngine.start()
|
||||
|
||||
guard let firstTimer = timerEngine.timerStates.keys.first else {
|
||||
XCTFail("No timers available")
|
||||
return
|
||||
}
|
||||
|
||||
let formatted = timerEngine.getFormattedTimeRemaining(for: firstTimer)
|
||||
XCTAssertFalse(formatted.isEmpty)
|
||||
XCTAssertTrue(formatted.contains(":"))
|
||||
}
|
||||
|
||||
// MARK: - Timer State Publisher Tests
|
||||
|
||||
func testTimerStatesPublisher() async throws {
|
||||
let expectation = XCTestExpectation(description: "Timer states changed")
|
||||
|
||||
timerEngine.$timerStates
|
||||
.dropFirst()
|
||||
.sink { states in
|
||||
if !states.isEmpty {
|
||||
expectation.fulfill()
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
timerEngine.start()
|
||||
|
||||
await fulfillment(of: [expectation], timeout: 1.0)
|
||||
}
|
||||
|
||||
func testActiveReminderPublisher() async throws {
|
||||
let expectation = XCTestExpectation(description: "Active reminder changed")
|
||||
|
||||
timerEngine.$activeReminder
|
||||
.dropFirst()
|
||||
.sink { reminder in
|
||||
if reminder != nil {
|
||||
expectation.fulfill()
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
timerEngine.start()
|
||||
|
||||
guard let firstTimer = timerEngine.timerStates.keys.first else {
|
||||
XCTFail("No timers available")
|
||||
return
|
||||
}
|
||||
|
||||
timerEngine.triggerReminder(for: firstTimer)
|
||||
|
||||
await fulfillment(of: [expectation], timeout: 1.0)
|
||||
}
|
||||
|
||||
// MARK: - System Sleep/Wake Tests
|
||||
|
||||
func testHandleSystemSleep() {
|
||||
timerEngine.start()
|
||||
let statesBefore = timerEngine.timerStates.count
|
||||
|
||||
timerEngine.handleSystemSleep()
|
||||
|
||||
// States should still exist
|
||||
XCTAssertEqual(timerEngine.timerStates.count, statesBefore)
|
||||
}
|
||||
|
||||
func testHandleSystemWake() {
|
||||
timerEngine.start()
|
||||
timerEngine.handleSystemSleep()
|
||||
timerEngine.handleSystemWake()
|
||||
|
||||
// Should handle wake event without crashing
|
||||
XCTAssertGreaterThan(timerEngine.timerStates.count, 0)
|
||||
}
|
||||
|
||||
// MARK: - Disabled Timer Tests
|
||||
|
||||
func testDisabledTimersNotInitialized() {
|
||||
var settings = AppSettings.defaults
|
||||
settings.lookAwayTimer.enabled = false
|
||||
settings.blinkTimer.enabled = false
|
||||
settings.postureTimer.enabled = false
|
||||
|
||||
let settingsManager = EnhancedMockSettingsManager(settings: settings)
|
||||
let engine = TimerEngine(settingsManager: settingsManager)
|
||||
|
||||
engine.start()
|
||||
|
||||
XCTAssertEqual(engine.timerStates.count, 0)
|
||||
}
|
||||
|
||||
func testPartiallyEnabledTimers() {
|
||||
var settings = AppSettings.defaults
|
||||
settings.lookAwayTimer.enabled = true
|
||||
settings.blinkTimer.enabled = false
|
||||
settings.postureTimer.enabled = false
|
||||
|
||||
let settingsManager = EnhancedMockSettingsManager(settings: settings)
|
||||
let engine = TimerEngine(settingsManager: settingsManager)
|
||||
|
||||
engine.start()
|
||||
|
||||
XCTAssertEqual(engine.timerStates.count, 1)
|
||||
}
|
||||
}
|
||||
62
GazeTests/Services/UsageTrackingServiceTests.swift
Normal file
62
GazeTests/Services/UsageTrackingServiceTests.swift
Normal file
@@ -0,0 +1,62 @@
|
||||
//
|
||||
// UsageTrackingServiceTests.swift
|
||||
// GazeTests
|
||||
//
|
||||
// Unit tests for UsageTrackingService.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import Gaze
|
||||
|
||||
@MainActor
|
||||
final class UsageTrackingServiceTests: XCTestCase {
|
||||
|
||||
var service: UsageTrackingService!
|
||||
|
||||
override func setUp() async throws {
|
||||
service = UsageTrackingService(resetThresholdMinutes: 60)
|
||||
}
|
||||
|
||||
override func tearDown() async throws {
|
||||
service = nil
|
||||
}
|
||||
|
||||
// MARK: - Initialization Tests
|
||||
|
||||
func testServiceInitialization() {
|
||||
XCTAssertNotNil(service)
|
||||
}
|
||||
|
||||
func testInitializationWithCustomThreshold() {
|
||||
let customService = UsageTrackingService(resetThresholdMinutes: 120)
|
||||
XCTAssertNotNil(customService)
|
||||
}
|
||||
|
||||
// MARK: - Threshold Tests
|
||||
|
||||
func testUpdateResetThreshold() {
|
||||
service.updateResetThreshold(minutes: 90)
|
||||
|
||||
// Should not crash
|
||||
XCTAssertNotNil(service)
|
||||
}
|
||||
|
||||
func testUpdateThresholdMultipleTimes() {
|
||||
service.updateResetThreshold(minutes: 30)
|
||||
service.updateResetThreshold(minutes: 60)
|
||||
service.updateResetThreshold(minutes: 120)
|
||||
|
||||
XCTAssertNotNil(service)
|
||||
}
|
||||
|
||||
// MARK: - Idle Monitoring Integration Tests
|
||||
|
||||
func testSetupIdleMonitoring() {
|
||||
let idleService = IdleMonitoringService(idleThresholdMinutes: 5)
|
||||
|
||||
service.setupIdleMonitoring(idleService)
|
||||
|
||||
// Should not crash
|
||||
XCTAssertNotNil(service)
|
||||
}
|
||||
}
|
||||
129
GazeTests/Services/WindowManagerTests.swift
Normal file
129
GazeTests/Services/WindowManagerTests.swift
Normal file
@@ -0,0 +1,129 @@
|
||||
//
|
||||
// WindowManagerTests.swift
|
||||
// GazeTests
|
||||
//
|
||||
// Unit tests for WindowManager service.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import XCTest
|
||||
@testable import Gaze
|
||||
|
||||
@MainActor
|
||||
final class WindowManagerTests: XCTestCase {
|
||||
|
||||
var windowManager: WindowManager!
|
||||
|
||||
override func setUp() async throws {
|
||||
windowManager = WindowManager.shared
|
||||
}
|
||||
|
||||
override func tearDown() async throws {
|
||||
windowManager.dismissAllReminders()
|
||||
windowManager = nil
|
||||
}
|
||||
|
||||
// MARK: - Initialization Tests
|
||||
|
||||
func testWindowManagerInitialization() {
|
||||
XCTAssertNotNil(windowManager)
|
||||
}
|
||||
|
||||
func testInitialState() {
|
||||
XCTAssertFalse(windowManager.isOverlayReminderVisible)
|
||||
XCTAssertFalse(windowManager.isSubtleReminderVisible)
|
||||
}
|
||||
|
||||
// MARK: - Window Visibility Tests
|
||||
|
||||
func testOverlayReminderVisibility() {
|
||||
XCTAssertFalse(windowManager.isOverlayReminderVisible)
|
||||
|
||||
let view = Text("Test Overlay")
|
||||
windowManager.showReminderWindow(view, windowType: .overlay)
|
||||
|
||||
XCTAssertTrue(windowManager.isOverlayReminderVisible)
|
||||
|
||||
windowManager.dismissOverlayReminder()
|
||||
XCTAssertFalse(windowManager.isOverlayReminderVisible)
|
||||
}
|
||||
|
||||
func testSubtleReminderVisibility() {
|
||||
XCTAssertFalse(windowManager.isSubtleReminderVisible)
|
||||
|
||||
let view = Text("Test Subtle")
|
||||
windowManager.showReminderWindow(view, windowType: .subtle)
|
||||
|
||||
XCTAssertTrue(windowManager.isSubtleReminderVisible)
|
||||
|
||||
windowManager.dismissSubtleReminder()
|
||||
XCTAssertFalse(windowManager.isSubtleReminderVisible)
|
||||
}
|
||||
|
||||
// MARK: - Multiple Window Tests
|
||||
|
||||
func testShowBothWindowTypes() {
|
||||
let overlayView = Text("Overlay")
|
||||
let subtleView = Text("Subtle")
|
||||
|
||||
windowManager.showReminderWindow(overlayView, windowType: .overlay)
|
||||
windowManager.showReminderWindow(subtleView, windowType: .subtle)
|
||||
|
||||
XCTAssertTrue(windowManager.isOverlayReminderVisible)
|
||||
XCTAssertTrue(windowManager.isSubtleReminderVisible)
|
||||
}
|
||||
|
||||
func testDismissAllReminders() {
|
||||
let overlayView = Text("Overlay")
|
||||
let subtleView = Text("Subtle")
|
||||
|
||||
windowManager.showReminderWindow(overlayView, windowType: .overlay)
|
||||
windowManager.showReminderWindow(subtleView, windowType: .subtle)
|
||||
|
||||
windowManager.dismissAllReminders()
|
||||
|
||||
XCTAssertFalse(windowManager.isOverlayReminderVisible)
|
||||
XCTAssertFalse(windowManager.isSubtleReminderVisible)
|
||||
}
|
||||
|
||||
// MARK: - Window Replacement Tests
|
||||
|
||||
func testReplaceOverlayWindow() {
|
||||
let firstView = Text("First Overlay")
|
||||
let secondView = Text("Second Overlay")
|
||||
|
||||
windowManager.showReminderWindow(firstView, windowType: .overlay)
|
||||
XCTAssertTrue(windowManager.isOverlayReminderVisible)
|
||||
|
||||
// Showing a new overlay should replace the old one
|
||||
windowManager.showReminderWindow(secondView, windowType: .overlay)
|
||||
XCTAssertTrue(windowManager.isOverlayReminderVisible)
|
||||
}
|
||||
|
||||
func testReplaceSubtleWindow() {
|
||||
let firstView = Text("First Subtle")
|
||||
let secondView = Text("Second Subtle")
|
||||
|
||||
windowManager.showReminderWindow(firstView, windowType: .subtle)
|
||||
XCTAssertTrue(windowManager.isSubtleReminderVisible)
|
||||
|
||||
windowManager.showReminderWindow(secondView, windowType: .subtle)
|
||||
XCTAssertTrue(windowManager.isSubtleReminderVisible)
|
||||
}
|
||||
|
||||
// MARK: - Integration with Settings Tests
|
||||
|
||||
func testShowSettingsWithSettingsManager() {
|
||||
let settingsManager = SettingsManager.shared
|
||||
|
||||
// Should not crash
|
||||
windowManager.showSettings(settingsManager: settingsManager, initialTab: 0)
|
||||
}
|
||||
|
||||
func testShowOnboardingWithSettingsManager() {
|
||||
let settingsManager = SettingsManager.shared
|
||||
|
||||
// Should not crash
|
||||
windowManager.showOnboarding(settingsManager: settingsManager)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user