## test_timer.nim ## ============== ## Tests unitaires de la machine à états du minuteur (module pur, sans Win32). import std/unittest import ../src/timer import ../src/config proc testProfile(): Profile = Profile(name: "Test", workMin: 25, shortBreakMin: 5, longBreakMin: 15, cycles: 4) suite "timer": test "initial state is idle": let t = initTimer() check t.phase == phIdle check t.remainingSecs == 0 check t.cycleCount == 0 test "startWork sets working phase and duration": var t = initTimer() t.startWork(testProfile()) check t.phase == phWorking check t.remainingSecs == 25 * 60 test "tick decrements remaining by one second": var t = initTimer() t.startWork(testProfile()) let ev = t.tick(testProfile()) check ev == evNone check t.remainingSecs == 25 * 60 - 1 test "tick does nothing when idle": var t = initTimer() check t.tick(testProfile()) == evNone check t.phase == phIdle test "work completion transitions to short break (1 cycle)": var t = initTimer() let p = Profile(name: "T", workMin: 1, shortBreakMin: 5, longBreakMin: 15, cycles: 4) t.startWork(p) var ev = evNone for i in 0 ..< 60: ev = t.tick(p) check ev == evWorkCompleted check t.phase == phShortBreak check t.remainingSecs == 5 * 60 check t.cycleCount == 1 test "break completion transitions back to work": var t = initTimer() let p = Profile(name: "T", workMin: 25, shortBreakMin: 1, longBreakMin: 15, cycles: 4) t.startBreak(p, longBreak = false) var ev = evNone for i in 0 ..< 60: ev = t.tick(p) check ev == evBreakCompleted check t.phase == phWorking check t.remainingSecs == 25 * 60 test "cyclesBeforeLongBreak triggers a long break": var t = initTimer() let p = Profile(name: "T", workMin: 1, shortBreakMin: 5, longBreakMin: 15, cycles: 4) t.cycleCount = 3 # la 4e période de travail doit déclencher la pause longue t.startWork(p) var ev = evNone for i in 0 ..< 60: ev = t.tick(p) check ev == evWorkCompleted check t.phase == phLongBreak check t.remainingSecs == 15 * 60 test "pause preserves the remaining time and resume restores phase": var t = initTimer() t.startWork(testProfile()) let before = t.remainingSecs t.pause() check t.phase == phPaused check t.remainingSecs == before t.resume() check t.phase == phWorking test "pause on idle does nothing": var t = initTimer() t.pause() check t.phase == phIdle test "stop returns to idle": var t = initTimer() t.startWork(testProfile()) t.stop() check t.phase == phIdle check t.remainingSecs == 0 test "stop resets cycleCount so long break timing stays correct": var t = initTimer() let p = Profile(name: "T", workMin: 1, shortBreakMin: 1, longBreakMin: 1, cycles: 4) t.cycleCount = 3 t.stop() check t.cycleCount == 0 # Après redémarrage, il faut 4 cycles (pas 1) avant la pause longue. t.startWork(p) check t.cycleCount == 0 test "isBreak is true only during breaks": var t = initTimer() check not t.isBreak() t.startWork(testProfile()) check not t.isBreak() t.startBreak(testProfile(), longBreak = false) check t.isBreak() t.startBreak(testProfile(), longBreak = true) check t.isBreak() test "skipBreak jumps from break to work": var t = initTimer() let p = testProfile() t.startBreak(p, longBreak = false) t.skipBreak(p) check t.phase == phWorking check t.remainingSecs == p.workMin * 60 test "skipBreak does nothing while working": var t = initTimer() t.startWork(testProfile()) t.skipBreak(testProfile()) check t.phase == phWorking test "extendBreak adds minutes to a break": var t = initTimer() t.startBreak(testProfile(), longBreak = false) let before = t.remainingSecs t.extendBreak(5) check t.remainingSecs == before + 5 * 60 test "extendBreak does nothing while working": var t = initTimer() t.startWork(testProfile()) t.extendBreak(5) check t.phase == phWorking test "formatTime formats minutes and seconds": check formatTime(0) == "0:00" check formatTime(65) == "1:05" check formatTime(3661) == "1:01:01"