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
This commit is contained in:
@@ -4,9 +4,45 @@
|
||||
//
|
||||
|
||||
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 = {
|
||||
|
||||
Reference in New Issue
Block a user