Files
OpenAppLock/OpenAppLockTests/RuleScheduleTests.swift
Brendan Chen 1d5e79ba7c refactor: rename app from Severed to OpenAppLock
Full rename ahead of App Store submission: project, targets, bundle
identifiers (dev.bchen.Severed -> dev.bchen.OpenAppLock), entitlements
file, app entry point, user-facing onboarding strings, test helpers,
and docs. Verified: all 62 unit tests pass.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-12 18:05:06 -04:00

122 lines
4.9 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//
// RuleScheduleTests.swift
// OpenAppLockTests
//
import Foundation
import Testing
@testable import OpenAppLock
@MainActor
@Suite("RuleSchedule window math")
struct RuleScheduleTests {
let nineToFiveWeekdays = RuleSchedule(
startMinutes: 9 * 60, endMinutes: 17 * 60, days: Weekday.weekdays
)
let overnight = RuleSchedule(
startMinutes: 22 * 60, endMinutes: 6 * 60, days: Weekday.everyDay
)
@Test("Active inside a same-day window")
func activeInsideWindow() {
let monday10am = date(2025, 1, 6, 10, 0)
let window = nineToFiveWeekdays.activeWindow(containing: monday10am, calendar: utc)
#expect(window?.start == date(2025, 1, 6, 9, 0))
#expect(window?.end == date(2025, 1, 6, 17, 0))
}
@Test("Inactive before the window starts and after it ends")
func inactiveOutsideWindow() {
#expect(!nineToFiveWeekdays.isActive(at: date(2025, 1, 6, 8, 59), calendar: utc))
#expect(!nineToFiveWeekdays.isActive(at: date(2025, 1, 6, 17, 0), calendar: utc))
}
@Test("Window start is inclusive, end is exclusive")
func boundaryInclusion() {
#expect(nineToFiveWeekdays.isActive(at: date(2025, 1, 6, 9, 0), calendar: utc))
#expect(!nineToFiveWeekdays.isActive(at: date(2025, 1, 6, 17, 0), calendar: utc))
}
@Test("Inactive on a disabled day")
func inactiveOnWeekend() {
#expect(!nineToFiveWeekdays.isActive(at: date(2025, 1, 11, 12, 0), calendar: utc))
}
@Test("Overnight window is active before and after midnight")
func overnightWindow() {
// Monday 23:30 inside Monday's 22:00 Tuesday 06:00 window.
let lateMonday = overnight.activeWindow(containing: date(2025, 1, 6, 23, 30), calendar: utc)
#expect(lateMonday?.start == date(2025, 1, 6, 22, 0))
#expect(lateMonday?.end == date(2025, 1, 7, 6, 0))
// Tuesday 02:00 still inside the window that started Monday.
let earlyTuesday = overnight.activeWindow(containing: date(2025, 1, 7, 2, 0), calendar: utc)
#expect(earlyTuesday?.start == date(2025, 1, 6, 22, 0))
#expect(earlyTuesday?.end == date(2025, 1, 7, 6, 0))
// The end boundary is exclusive: Tuesday 06:00 is outside Monday's window.
#expect(overnight.activeWindow(containing: date(2025, 1, 7, 6, 0), calendar: utc) == nil)
}
@Test("Overnight window belongs to the day it starts on")
func overnightDayOwnership() {
let mondayOnly = RuleSchedule(
startMinutes: 22 * 60, endMinutes: 6 * 60, days: [.monday]
)
// Tuesday 03:00 is inside Monday's window.
#expect(mondayOnly.isActive(at: date(2025, 1, 7, 3, 0), calendar: utc))
// Wednesday 03:00 would be Tuesday's window Tuesday is disabled.
#expect(!mondayOnly.isActive(at: date(2025, 1, 8, 3, 0), calendar: utc))
// Monday 23:00 is inside Monday's window.
#expect(mondayOnly.isActive(at: date(2025, 1, 6, 23, 0), calendar: utc))
}
@Test("Equal start and end means a 24-hour window")
func fullDayWindow() {
let allDay = RuleSchedule(startMinutes: 600, endMinutes: 600, days: [.monday])
#expect(allDay.durationMinutes == 24 * 60)
#expect(allDay.isActive(at: date(2025, 1, 7, 9, 59), calendar: utc))
#expect(!allDay.isActive(at: date(2025, 1, 7, 10, 0), calendar: utc))
}
@Test("Next start on the same day")
func nextStartSameDay() {
let next = nineToFiveWeekdays.nextStart(after: date(2025, 1, 6, 8, 0), calendar: utc)
#expect(next == date(2025, 1, 6, 9, 0))
}
@Test("Next start skips disabled days")
func nextStartSkipsWeekend() {
let next = nineToFiveWeekdays.nextStart(after: date(2025, 1, 11, 12, 0), calendar: utc)
#expect(next == date(2025, 1, 13, 9, 0))
}
@Test("Next start is strictly after the given moment")
func nextStartStrictlyAfter() {
let next = nineToFiveWeekdays.nextStart(after: date(2025, 1, 6, 9, 0), calendar: utc)
#expect(next == date(2025, 1, 7, 9, 0))
}
@Test("No days means no windows and no next start")
func emptyDays() {
let never = RuleSchedule(startMinutes: 540, endMinutes: 1020, days: [])
#expect(!never.isActive(at: date(2025, 1, 6, 10, 0), calendar: utc))
#expect(never.nextStart(after: date(2025, 1, 6, 10, 0), calendar: utc) == nil)
}
@Test("Duration handles normal and overnight windows")
func duration() {
#expect(nineToFiveWeekdays.durationMinutes == 8 * 60)
#expect(overnight.durationMinutes == 8 * 60)
}
@Test("Time labels are zero-padded 24h")
func timeLabels() {
#expect(RuleSchedule.timeLabel(forMinutes: 9 * 60) == "09:00")
#expect(RuleSchedule.timeLabel(forMinutes: 17 * 60 + 5) == "17:05")
#expect(RuleSchedule.timeLabel(forMinutes: 0) == "00:00")
#expect(nineToFiveWeekdays.timeRangeLabel == "09:00 17:00")
}
}