feat: Working on mocks and mock storage.

This commit is contained in:
2025-01-16 17:00:19 -05:00
parent b6e7fe915f
commit 09b46f672a
4 changed files with 142 additions and 7 deletions

View File

@@ -14,7 +14,7 @@
private var storage: [Model.ID: Model]
private let modelFromCreate: @Sendable (Create) -> Model
private let modelFromCreate: @Sendable (Create) async throws -> Model
private let fetchToPredicate: @Sendable (Fetch) -> ((Model) -> Bool)
private let fetchExtras: @Sendable (Fetch, [Model]) async throws -> [Model]
private let applyUpdates: @Sendable (inout Model, Update, Get?) async throws -> Void
@@ -22,7 +22,7 @@
init(
_ mocks: [Model] = [],
create modelFromCreate: @Sendable @escaping (Create) -> Model,
create modelFromCreate: @Sendable @escaping (Create) async throws -> Model,
fetch fetchToPredicate: @Sendable @escaping (Fetch) -> ((Model) -> Bool),
fetchExtras: @Sendable @escaping (Fetch, [Model]) async throws -> [Model] = { $1 },
get getExtras: @Sendable @escaping (Get?, Model) async throws -> Model,
@@ -41,7 +41,7 @@
}
func create(_ create: Create) async throws -> Model {
let model = modelFromCreate(create)
let model = try await modelFromCreate(create)
storage[model.id] = model
return model
}
@@ -75,7 +75,7 @@
extension MockStorage where Get == Void {
init(
_ mocks: [Model] = [],
create modelFromCreate: @Sendable @escaping (Create) -> Model,
create modelFromCreate: @Sendable @escaping (Create) async throws -> Model,
fetch fetchToPredicate: @Sendable @escaping (Fetch) -> ((Model) -> Bool),
fetchExtras: @Sendable @escaping (Fetch, [Model]) async throws -> [Model] = { $1 },
update applyUpdates: @Sendable @escaping (inout Model, Update) async throws -> Void
@@ -103,7 +103,7 @@
extension MockStorage where Fetch == Void {
init(
_ mocks: [Model] = [],
create modelFromCreate: @Sendable @escaping (Create) -> Model,
create modelFromCreate: @Sendable @escaping (Create) async throws -> Model,
fetchExtras: @Sendable @escaping (Fetch, [Model]) async throws -> [Model] = { $1 },
get getExtras: @Sendable @escaping (Get?, Model) async throws -> Model,
update applyUpdates: @Sendable @escaping (inout Model, Update, Get?) async throws -> Void
@@ -126,7 +126,7 @@
extension MockStorage where Fetch == Void, Get == Void {
init(
_ mocks: [Model] = [],
create modelFromCreate: @Sendable @escaping (Create) -> Model,
create modelFromCreate: @Sendable @escaping (Create) async throws -> Model,
fetchExtras: @Sendable @escaping (Fetch, [Model]) async throws -> [Model] = { $1 },
update applyUpdates: @Sendable @escaping (inout Model, Update) async throws -> Void
) {
@@ -138,6 +138,5 @@
update: { model, updates, _ in try await applyUpdates(&model, updates) }
)
}
}
#endif

View File

@@ -22,3 +22,74 @@ extension PurchaseOrder.Create: Content {}
extension DatabaseClient.PurchaseOrders: TestDependencyKey {
public static let testValue: DatabaseClient.PurchaseOrders = Self()
}
#if DEBUG
typealias PurchaseOrderMockStorage = MockStorage<
PurchaseOrder,
PurchaseOrder.Create,
Void,
Void,
Void
>
public extension DependencyValues {
var purchaseOrderID: PurchaseOrderIDGenerator {
get { self[PurchaseOrderIDGenerator.self] }
set { self[PurchaseOrderIDGenerator.self] = newValue }
}
}
@DependencyClient
public struct PurchaseOrderIDGenerator: Sendable {
var nextID: @Sendable () async throws -> Int
}
extension PurchaseOrderIDGenerator: DependencyKey {
public static let testValue: PurchaseOrderIDGenerator = .liveValue
public static var liveValue: Self {
let counter = Counter()
return .init(nextID: { await counter.nextID() })
}
actor Counter {
private var count: Int
init(starting: Int = 1) {
self.count = starting
}
func nextID() async -> Int {
count += 1
return count
}
}
}
// private extension PurchaseOrderMockStorage {
// static func make(_ mocks: [PurchaseOrder]) -> Self {
// @Dependency(\.date.now) var now
// @Dependency(\.purchaseOrderID) var purchaseOrderID
//
// return .init(
// mocks,
// create: { model in
// try await PurchaseOrder(
// id: purchaseOrderID.nextID(),
// workOrder: model.workOrder,
// materials: model.materials,
// customer: model.customer,
// truckStock: model.truckStock,
// createdBy: model.createdForID,
// createdFor: model.createdForID,
// vendorBranch: .i
//
// )
// },
// update: { _, _ in
// fatalError()
// }
// )
// }
// }
#endif

View File

@@ -28,3 +28,66 @@ extension User.Update: Content {}
extension DatabaseClient.Users: TestDependencyKey {
public static let testValue: DatabaseClient.Users = Self()
}
#if DEBUG
typealias UserMockStorage = MockStorage<
User,
User.Create,
Void,
Void,
User.Update
>
private extension UserMockStorage {
static func make(_ mocks: [User]) -> Self {
@Dependency(\.date.now) var now
@Dependency(\.uuid) var uuid
return .init(
create: { model in
User(
id: uuid(),
email: model.email,
username: model.username,
createdAt: now,
updatedAt: now
)
},
update: { model, updates in
let user = User(
id: model.id,
email: updates.email ?? model.email,
username: updates.username ?? model.username,
createdAt: model.createdAt,
updatedAt: now
)
model = user
}
)
}
}
public extension User.Token {
static func mock(id: User.ID) -> Self {
.init(id: UUID(0), userID: id, value: "test")
}
}
public extension DatabaseClient.Users {
static func mock(_ mocks: [User]) -> Self {
let storage = UserMockStorage.make(mocks)
return .init(
count: { try await storage.count() },
create: { try await storage.create($0) },
delete: { try await storage.delete($0) },
fetchAll: { try await storage.fetchAll() },
get: { try await storage.get($0) },
login: { _ in .mock(id: UUID(0)) },
logout: { _ in },
token: { .mock(id: $0) },
update: { try await storage.update($0, $1) }
)
}
}
#endif