Files
OpenAppLock/OpenAppLockTests/TestSupport.swift
Brendan Chen d8d7028d60 feat: introduce reusable app lists for rules
- AppList @Model with launch migration from legacy inline selections
  (rules with identical selections share one list; idempotent)
- rules point at one app list; Block/Allow Only belongs to the rule and
  is offered only in the Schedule editor (limit kinds sanitize to Block)
- app-list picker sheet (select / create / edit / delete with in-use
  protection) replaces the per-rule selection sheet
- Hard Mode locks app-list editing while any hard rule is blocking
- SwiftData stability: relationships are only wired between managed
  models, and unit tests share one in-memory container (fresh context +
  data wipe per test) — per-test container creation trapped
  intermittently inside SwiftData

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-12 20:02:35 -04:00

73 lines
2.4 KiB
Swift
Raw Permalink 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.
//
// TestSupport.swift
// OpenAppLockTests
//
import Foundation
import SwiftData
@testable import OpenAppLock
/// One in-memory ModelContainer shared by the whole test process.
///
/// Repeatedly creating containers for this schema (inverse relationships)
/// trips an intermittent EXC_BREAKPOINT inside SwiftData's configuration
/// setup observed both in test runs and in a sequential snippet that made
/// six containers. Tests therefore share a single container; isolation comes
/// from a fresh ModelContext plus a data wipe per test.
@MainActor
private let sharedTestContainer: ModelContainer = {
do {
return try ModelContainer(
for: Schema([BlockingRule.self, AppList.self]),
configurations: ModelConfiguration(isStoredInMemoryOnly: true)
)
} catch {
fatalError("Could not create the shared test ModelContainer: \(error)")
}
}()
/// Fresh, empty SwiftData context for model tests. The wipe deletes object
/// by object batch `delete(model:)` refuses to fire the appList nullify
/// inverse ("Constraint trigger violation").
@MainActor
func makeInMemoryContext() throws -> ModelContext {
let context = ModelContext(sharedTestContainer)
for rule in try context.fetch(FetchDescriptor<BlockingRule>()) {
context.delete(rule)
}
for list in try context.fetch(FetchDescriptor<AppList>()) {
context.delete(list)
}
try context.save()
return context
}
/// Fixed UTC gregorian calendar so schedule math is deterministic regardless
/// of the machine running the tests.
let utc: Calendar = {
var calendar = Calendar(identifier: .gregorian)
calendar.timeZone = TimeZone(identifier: "UTC")!
return calendar
}()
/// Builds a date in the UTC test calendar. 2025-01-06 is a Monday; the tests
/// use that week (Jan 612, 2025) as their anchor.
func date(
_ year: Int, _ month: Int, _ day: Int, _ hour: Int = 0, _ minute: Int = 0
) -> Date {
utc.date(
from: DateComponents(year: year, month: month, day: day, hour: hour, minute: minute)
)!
}
/// Monday of the anchor week.
enum AnchorWeek {
static let monday = (year: 2025, month: 1, day: 6)
static let tuesday = (year: 2025, month: 1, day: 7)
static let wednesday = (year: 2025, month: 1, day: 8)
static let saturday = (year: 2025, month: 1, day: 11)
static let sunday = (year: 2025, month: 1, day: 12)
static let nextMonday = (year: 2025, month: 1, day: 13)
}