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.
This commit is contained in:
2026-06-12 18:05:06 -04:00
parent af919c1585
commit e91d8344a9
42 changed files with 145 additions and 145 deletions

View File

@@ -0,0 +1,126 @@
//
// RuleEnforcerTests.swift
// OpenAppLockTests
//
import Foundation
import Testing
@testable import OpenAppLock
@MainActor
@Suite("Rule enforcement → shields")
struct RuleEnforcerTests {
let mondayDuringWork = date(2025, 1, 6, 10, 0)
let mondayEvening = date(2025, 1, 6, 19, 0)
@Test("Active schedule rules are shielded; inactive ones are not")
func shieldsActiveRules() {
let shields = MockShieldController()
let enforcer = RuleEnforcer(shields: shields)
let active = BlockingRule(name: "Work Time")
let weekendOnly = BlockingRule(name: "Weekend Zen", days: Weekday.weekends)
enforcer.refresh(rules: [active, weekendOnly], at: mondayDuringWork, calendar: utc)
#expect(shields.shieldedRuleIDs == [active.id])
#expect(enforcer.blockingRuleIDs == [active.id])
}
@Test("Disabled rules are never shielded")
func skipsDisabledRules() {
let shields = MockShieldController()
let enforcer = RuleEnforcer(shields: shields)
let rule = BlockingRule(name: "Work Time", isEnabled: false)
enforcer.refresh(rules: [rule], at: mondayDuringWork, calendar: utc)
#expect(shields.shieldedRuleIDs.isEmpty)
}
@Test("Paused rules are not shielded")
func skipsPausedRules() {
let shields = MockShieldController()
let enforcer = RuleEnforcer(shields: shields)
let rule = BlockingRule(name: "Work Time")
RulePolicy.unblock(rule, at: mondayDuringWork, calendar: utc)
enforcer.refresh(rules: [rule], at: mondayDuringWork, calendar: utc)
#expect(shields.shieldedRuleIDs.isEmpty)
}
@Test("Time-limit rules are not schedule-shielded")
func skipsTimeLimitRules() {
let shields = MockShieldController()
let enforcer = RuleEnforcer(shields: shields)
let rule = BlockingRule(name: "Time Keeper", kind: .timeLimit)
enforcer.refresh(rules: [rule], at: mondayDuringWork, calendar: utc)
#expect(shields.shieldedRuleIDs.isEmpty)
}
@Test("Shields are cleared when a window ends")
func clearsShieldAfterWindow() {
let shields = MockShieldController()
let enforcer = RuleEnforcer(shields: shields)
let rule = BlockingRule(name: "Work Time")
enforcer.refresh(rules: [rule], at: mondayDuringWork, calendar: utc)
#expect(shields.shieldedRuleIDs == [rule.id])
enforcer.refresh(rules: [rule], at: mondayEvening, calendar: utc)
#expect(shields.shieldedRuleIDs.isEmpty)
#expect(enforcer.blockingRuleIDs.isEmpty)
}
@Test("Shields are cleared when a rule is deleted")
func clearsShieldAfterDeletion() {
let shields = MockShieldController()
let enforcer = RuleEnforcer(shields: shields)
let rule = BlockingRule(name: "Work Time")
enforcer.refresh(rules: [rule], at: mondayDuringWork, calendar: utc)
enforcer.refresh(rules: [], at: mondayDuringWork, calendar: utc)
#expect(shields.shieldedRuleIDs.isEmpty)
}
@Test("Expired pauses are cleaned up during refresh")
func clearsExpiredPause() {
let shields = MockShieldController()
let enforcer = RuleEnforcer(shields: shields)
let rule = BlockingRule(name: "Work Time")
rule.pausedUntil = date(2025, 1, 6, 9, 30)
enforcer.refresh(rules: [rule], at: mondayDuringWork, calendar: utc)
#expect(rule.pausedUntil == nil)
#expect(shields.shieldedRuleIDs == [rule.id])
}
@Test("The selection mode is forwarded to the shield layer")
func forwardsSelectionMode() {
let shields = MockShieldController()
let enforcer = RuleEnforcer(shields: shields)
let rule = BlockingRule(name: "Focus", selectionMode: .allowOnly)
enforcer.refresh(rules: [rule], at: mondayDuringWork, calendar: utc)
#expect(shields.appliedModes[rule.id] == .allowOnly)
}
@Test("The adult-content flag is forwarded to the shield layer")
func forwardsAdultContentFlag() {
let shields = MockShieldController()
let enforcer = RuleEnforcer(shields: shields)
let filtered = BlockingRule(name: "Clean Mode", blockAdultContent: true)
let unfiltered = BlockingRule(name: "Plain")
enforcer.refresh(rules: [filtered, unfiltered], at: mondayDuringWork, calendar: utc)
#expect(shields.appliedAdultContentFlags[filtered.id] == true)
#expect(shields.appliedAdultContentFlags[unfiltered.id] == false)
}
}