learning_ai_clock/ios/ChronoMindTests/SharedTimerDataTests.swift
saravanakumardb1 995cdb8e7d fix(ios): align tests with current PomodoroConfig/PomodoroState/CreateCountdownParams signatures
- PomodoroConfig: add longBreakMinutes parameter
- PomodoroState: add isLongBreak, completedRounds parameters; remove roundStartedAt
- CreateCountdownParams: duration → durationSeconds
- RescheduleEngineTests: compare timeIntervalSince1970 (not Date) with accuracy
2026-03-21 08:34:50 -07:00

236 lines
9.8 KiB
Swift

// SharedTimerData Tests
import XCTest
@testable import ChronoMind
final class SharedTimerDataTests: XCTestCase {
// MARK: - TimerSnapshot Conversion
func testCMTimerToSnapshot() {
let now = Date()
let target = now.addingTimeInterval(3600)
let warning = CascadeWarning(
id: "w1",
minutesBefore: 10,
fired: true,
firedAt: now.addingTimeInterval(-600),
scheduledTime: now.addingTimeInterval(-600)
)
let warning2 = CascadeWarning(
id: "w2",
minutesBefore: 5,
fired: false,
firedAt: nil,
scheduledTime: target.addingTimeInterval(-300)
)
var timer = createAlarm(CreateAlarmParams(
label: "Test Alarm",
targetTime: target,
urgency: .important
))
timer.warnings = [warning, warning2]
timer.pomodoroConfig = PomodoroConfig(workMinutes: 25, breakMinutes: 5, longBreakMinutes: 15, rounds: 4)
timer.pomodoroState = PomodoroState(currentRound: 2, isBreak: false, isLongBreak: false, completedRounds: 1)
let snapshot = timer.toSnapshot()
XCTAssertEqual(snapshot.id, timer.id)
XCTAssertEqual(snapshot.label, "Test Alarm")
XCTAssertEqual(snapshot.type, .alarm)
XCTAssertEqual(snapshot.urgency, .important)
XCTAssertEqual(snapshot.state, .active)
XCTAssertEqual(snapshot.targetTime, target)
XCTAssertEqual(snapshot.totalWarnings, 2)
XCTAssertEqual(snapshot.firedWarnings, 1)
XCTAssertEqual(snapshot.nextWarningTime, target.addingTimeInterval(-300))
XCTAssertEqual(snapshot.pomodoroCurrentRound, 2)
XCTAssertEqual(snapshot.pomodoroTotalRounds, 4)
XCTAssertEqual(snapshot.pomodoroIsBreak, false)
}
func testSnapshotWithNoWarnings() {
let now = Date()
let target = now.addingTimeInterval(600)
let timer = createCountdown(CreateCountdownParams(
label: "Quick",
durationSeconds: 600,
urgency: .gentle
))
let snapshot = timer.toSnapshot()
XCTAssertEqual(snapshot.label, "Quick")
XCTAssertEqual(snapshot.type, .countdown)
XCTAssertEqual(snapshot.urgency, .gentle)
XCTAssertNil(snapshot.pomodoroCurrentRound)
XCTAssertNil(snapshot.pomodoroTotalRounds)
}
// MARK: - TimerSnapshot Helpers
func testRemainingSeconds() {
let target = Date().addingTimeInterval(120)
let snapshot = TimerSnapshot(
id: "t1", label: "Test", type: .countdown, urgency: .standard,
state: .active, targetTime: target, duration: 120,
startedAt: Date(), elapsedBeforePause: 0, snoozeCount: 0,
category: nil, pomodoroCurrentRound: nil, pomodoroTotalRounds: nil,
pomodoroIsBreak: nil, nextWarningTime: nil, totalWarnings: 0, firedWarnings: 0
)
let remaining = snapshot.remainingSeconds()
XCTAssertGreaterThan(remaining, 118)
XCTAssertLessThanOrEqual(remaining, 120)
}
func testRemainingSecondsPaused() {
let target = Date().addingTimeInterval(300)
let snapshot = TimerSnapshot(
id: "t2", label: "Paused", type: .countdown, urgency: .standard,
state: .paused, targetTime: target, duration: 600,
startedAt: Date(), elapsedBeforePause: 200, snoozeCount: 0,
category: nil, pomodoroCurrentRound: nil, pomodoroTotalRounds: nil,
pomodoroIsBreak: nil, nextWarningTime: nil, totalWarnings: 0, firedWarnings: 0
)
// When paused, remaining = duration - elapsedBeforePause
let remaining = snapshot.remainingSeconds()
XCTAssertEqual(remaining, 400)
}
func testHasFired() {
let pastTarget = Date().addingTimeInterval(-10)
let snapshot = TimerSnapshot(
id: "t3", label: "Fired", type: .alarm, urgency: .critical,
state: .firing, targetTime: pastTarget, duration: nil,
startedAt: nil, elapsedBeforePause: 0, snoozeCount: 0,
category: nil, pomodoroCurrentRound: nil, pomodoroTotalRounds: nil,
pomodoroIsBreak: nil, nextWarningTime: nil, totalWarnings: 0, firedWarnings: 0
)
XCTAssertTrue(snapshot.hasFired())
}
func testHasNotFired() {
let futureTarget = Date().addingTimeInterval(3600)
let snapshot = TimerSnapshot(
id: "t4", label: "Active", type: .alarm, urgency: .standard,
state: .active, targetTime: futureTarget, duration: nil,
startedAt: nil, elapsedBeforePause: 0, snoozeCount: 0,
category: nil, pomodoroCurrentRound: nil, pomodoroTotalRounds: nil,
pomodoroIsBreak: nil, nextWarningTime: nil, totalWarnings: 0, firedWarnings: 0
)
XCTAssertFalse(snapshot.hasFired())
}
func testRemainingCompact() {
let target = Date().addingTimeInterval(3600)
let snapshot = TimerSnapshot(
id: "t5", label: "Hour", type: .countdown, urgency: .standard,
state: .active, targetTime: target, duration: 3600,
startedAt: Date(), elapsedBeforePause: 0, snoozeCount: 0,
category: nil, pomodoroCurrentRound: nil, pomodoroTotalRounds: nil,
pomodoroIsBreak: nil, nextWarningTime: nil, totalWarnings: 0, firedWarnings: 0
)
let compact = snapshot.remainingCompact()
// Should be something like "59m" or "1h"
XCTAssertFalse(compact.isEmpty)
}
// MARK: - Snapshot Codable
func testSnapshotEncodeDecode() throws {
let snapshot = TimerSnapshot(
id: "codec-test", label: "Encode Me", type: .pomodoro, urgency: .critical,
state: .warning, targetTime: Date().addingTimeInterval(500), duration: 1500,
startedAt: Date(), elapsedBeforePause: 100, snoozeCount: 1,
category: "work", pomodoroCurrentRound: 3, pomodoroTotalRounds: 4,
pomodoroIsBreak: false, nextWarningTime: Date().addingTimeInterval(200),
totalWarnings: 3, firedWarnings: 2
)
let encoder = JSONEncoder()
let data = try encoder.encode(snapshot)
let decoder = JSONDecoder()
let decoded = try decoder.decode(TimerSnapshot.self, from: data)
XCTAssertEqual(decoded.id, "codec-test")
XCTAssertEqual(decoded.label, "Encode Me")
XCTAssertEqual(decoded.type, .pomodoro)
XCTAssertEqual(decoded.urgency, .critical)
XCTAssertEqual(decoded.state, .warning)
XCTAssertEqual(decoded.duration, 1500)
XCTAssertEqual(decoded.elapsedBeforePause, 100)
XCTAssertEqual(decoded.snoozeCount, 1)
XCTAssertEqual(decoded.category, "work")
XCTAssertEqual(decoded.pomodoroCurrentRound, 3)
XCTAssertEqual(decoded.pomodoroTotalRounds, 4)
XCTAssertEqual(decoded.pomodoroIsBreak, false)
XCTAssertEqual(decoded.totalWarnings, 3)
XCTAssertEqual(decoded.firedWarnings, 2)
}
func testSnapshotArrayEncodeDecode() throws {
let snapshots = [
TimerSnapshot(
id: "a1", label: "Timer A", type: .alarm, urgency: .important,
state: .active, targetTime: Date().addingTimeInterval(1000), duration: nil,
startedAt: nil, elapsedBeforePause: 0, snoozeCount: 0,
category: nil, pomodoroCurrentRound: nil, pomodoroTotalRounds: nil,
pomodoroIsBreak: nil, nextWarningTime: nil, totalWarnings: 0, firedWarnings: 0
),
TimerSnapshot(
id: "a2", label: "Timer B", type: .countdown, urgency: .gentle,
state: .paused, targetTime: Date().addingTimeInterval(2000), duration: 2000,
startedAt: Date(), elapsedBeforePause: 500, snoozeCount: 0,
category: nil, pomodoroCurrentRound: nil, pomodoroTotalRounds: nil,
pomodoroIsBreak: nil, nextWarningTime: nil, totalWarnings: 1, firedWarnings: 0
),
]
let data = try JSONEncoder().encode(snapshots)
let decoded = try JSONDecoder().decode([TimerSnapshot].self, from: data)
XCTAssertEqual(decoded.count, 2)
XCTAssertEqual(decoded[0].id, "a1")
XCTAssertEqual(decoded[1].id, "a2")
XCTAssertEqual(decoded[1].state, .paused)
}
// MARK: - Equatable
func testSnapshotEquatable() {
let s1 = TimerSnapshot(
id: "eq1", label: "A", type: .alarm, urgency: .standard,
state: .active, targetTime: Date(), duration: nil,
startedAt: nil, elapsedBeforePause: 0, snoozeCount: 0,
category: nil, pomodoroCurrentRound: nil, pomodoroTotalRounds: nil,
pomodoroIsBreak: nil, nextWarningTime: nil, totalWarnings: 0, firedWarnings: 0
)
let s2 = TimerSnapshot(
id: "eq1", label: "B", type: .countdown, urgency: .critical,
state: .firing, targetTime: Date(), duration: 100,
startedAt: nil, elapsedBeforePause: 0, snoozeCount: 0,
category: nil, pomodoroCurrentRound: nil, pomodoroTotalRounds: nil,
pomodoroIsBreak: nil, nextWarningTime: nil, totalWarnings: 0, firedWarnings: 0
)
let s3 = TimerSnapshot(
id: "eq2", label: "A", type: .alarm, urgency: .standard,
state: .active, targetTime: Date(), duration: nil,
startedAt: nil, elapsedBeforePause: 0, snoozeCount: 0,
category: nil, pomodoroCurrentRound: nil, pomodoroTotalRounds: nil,
pomodoroIsBreak: nil, nextWarningTime: nil, totalWarnings: 0, firedWarnings: 0
)
// Same id = equal
XCTAssertEqual(s1, s2)
// Different id = not equal
XCTAssertNotEqual(s1, s3)
}
}