feat: Begins live database client tests.
All checks were successful
CI / Linux Tests (push) Successful in 5m35s
All checks were successful
CI / Linux Tests (push) Successful in 5m35s
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -13,3 +13,4 @@ tailwindcss
|
||||
*.pdf
|
||||
.env
|
||||
.env*
|
||||
default.profraw
|
||||
|
||||
@@ -87,7 +87,15 @@ let package = Package(
|
||||
.product(name: "Vapor", package: "vapor"),
|
||||
]
|
||||
),
|
||||
|
||||
.testTarget(
|
||||
name: "DatabaseClientTests",
|
||||
dependencies: [
|
||||
.target(name: "App"),
|
||||
.target(name: "DatabaseClient"),
|
||||
.product(name: "DependenciesTestSupport", package: "swift-dependencies"),
|
||||
.product(name: "FluentSQLiteDriver", package: "fluent-sqlite-driver"),
|
||||
]
|
||||
),
|
||||
.target(
|
||||
name: "EnvClient",
|
||||
dependencies: [
|
||||
|
||||
@@ -65,9 +65,7 @@ private func setupDatabase(
|
||||
|
||||
let databaseClient = makeDatabaseClient(app.db)
|
||||
|
||||
if app.environment != .testing {
|
||||
try await app.migrations.add(databaseClient.migrations())
|
||||
}
|
||||
|
||||
return databaseClient
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import DependenciesMacros
|
||||
import Fluent
|
||||
import Foundation
|
||||
import ManualDCore
|
||||
import SQLKit
|
||||
|
||||
extension DatabaseClient.ComponentLosses: TestDependencyKey {
|
||||
public static let testValue = Self()
|
||||
|
||||
@@ -11,12 +11,12 @@ extension Snapshotting where Value == (any HTML), Format == String {
|
||||
}
|
||||
}
|
||||
|
||||
extension Snapshotting where Value == String, Format == String {
|
||||
public static var html: Snapshotting {
|
||||
var snapshotting = SimplySnapshotting.lines
|
||||
.pullback { $0 }
|
||||
|
||||
snapshotting.pathExtension = "html"
|
||||
return snapshotting
|
||||
}
|
||||
}
|
||||
// extension Snapshotting where Value == String, Format == String {
|
||||
// public static var html: Snapshotting {
|
||||
// var snapshotting = SimplySnapshotting.lines
|
||||
// .pullback { $0 }
|
||||
//
|
||||
// snapshotting.pathExtension = "html"
|
||||
// return snapshotting
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -32,8 +32,7 @@ public struct PdfClient: Sendable {
|
||||
/// - Parameters:
|
||||
/// - request: The project data used to generate the pdf.
|
||||
public func generatePdf(request: Request) async throws -> Response {
|
||||
let html = try await self.html(request)
|
||||
return try await self.generatePdf(request.project.id, html)
|
||||
try await self.generatePdf(request.project.id, html(request))
|
||||
}
|
||||
|
||||
}
|
||||
@@ -76,17 +75,26 @@ extension PdfClient: DependencyKey {
|
||||
}
|
||||
|
||||
extension PdfClient {
|
||||
/// Container for the data required to generate a pdf for a given project.
|
||||
/// Represents the data required to generate a pdf for a given project.
|
||||
public struct Request: Codable, Equatable, Sendable {
|
||||
|
||||
/// The project we're generating a pdf for.
|
||||
public let project: Project
|
||||
/// The rooms in the project.
|
||||
public let rooms: [Room]
|
||||
/// The component pressure losses for the project.
|
||||
public let componentLosses: [ComponentPressureLoss]
|
||||
/// The calculated duct sizes for the project.
|
||||
public let ductSizes: DuctSizes
|
||||
/// The equipment information for the project.
|
||||
public let equipmentInfo: EquipmentInfo
|
||||
/// The max supply equivalent length for the project.
|
||||
public let maxSupplyTEL: EquivalentLength
|
||||
/// The max return equivalent length for the project.
|
||||
public let maxReturnTEL: EquivalentLength
|
||||
/// The calculated design friction rate for the project.
|
||||
public let frictionRate: FrictionRate
|
||||
/// The project wide sensible heat ratio.
|
||||
public let projectSHR: Double
|
||||
|
||||
var totalEquivalentLength: Double {
|
||||
@@ -116,9 +124,12 @@ extension PdfClient {
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the response after generating a pdf.
|
||||
public struct Response: Equatable, Sendable {
|
||||
|
||||
/// The path to the html file used to generate the pdf from.
|
||||
public let htmlPath: String
|
||||
/// The path to the pdf file.
|
||||
public let pdfPath: String
|
||||
|
||||
public init(htmlPath: String, pdfPath: String) {
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import Foundation
|
||||
|
||||
public struct ProjectClientError: Error {
|
||||
public let reason: String
|
||||
|
||||
public init(_ reason: String) {
|
||||
self.reason = reason
|
||||
}
|
||||
}
|
||||
@@ -18,9 +18,12 @@ extension DependencyValues {
|
||||
/// for the view controller to render views.
|
||||
@DependencyClient
|
||||
public struct ProjectClient: Sendable {
|
||||
public var calculateDuctSizes: @Sendable (Project.ID) async throws -> DuctSizes
|
||||
|
||||
/// Calculates the room duct sizes for the given project.
|
||||
public var calculateRoomDuctSizes:
|
||||
@Sendable (Project.ID) async throws -> [DuctSizes.RoomContainer]
|
||||
|
||||
/// Calculates the trunk duct sizes for the given project.
|
||||
public var calculateTrunkDuctSizes:
|
||||
@Sendable (Project.ID) async throws -> [DuctSizes.TrunkContainer]
|
||||
|
||||
@@ -28,6 +31,14 @@ public struct ProjectClient: Sendable {
|
||||
@Sendable (User.ID, Project.Create) async throws -> CreateProjectResponse
|
||||
|
||||
public var frictionRate: @Sendable (Project.ID) async throws -> FrictionRateResponse
|
||||
public var generatePdf: @Sendable (Project.ID) async throws -> Response
|
||||
|
||||
public func calculateDuctSizes(_ projectID: Project.ID) async throws -> DuctSizes {
|
||||
.init(
|
||||
rooms: try await calculateRoomDuctSizes(projectID),
|
||||
trunks: try await calculateTrunkDuctSizes(projectID)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension ProjectClient: TestDependencyKey {
|
||||
|
||||
@@ -9,32 +9,18 @@ extension DatabaseClient {
|
||||
details: Project.Detail
|
||||
) async throws -> (DuctSizes, DuctSizeSharedRequest) {
|
||||
let (rooms, shared) = try await calculateRoomDuctSizes(details: details)
|
||||
let (trunks, _) = try await calculateTrunkDuctSizes(details: details)
|
||||
return (.init(rooms: rooms, trunks: trunks), shared)
|
||||
}
|
||||
|
||||
func calculateDuctSizes(
|
||||
projectID: Project.ID
|
||||
) async throws -> (DuctSizes, DuctSizeSharedRequest, [Room]) {
|
||||
@Dependency(\.manualD) var manualD
|
||||
|
||||
let shared = try await sharedDuctRequest(projectID)
|
||||
let rooms = try await rooms.fetch(projectID)
|
||||
|
||||
return try await (
|
||||
manualD.calculateDuctSizes(
|
||||
.init(
|
||||
rooms: rooms,
|
||||
trunks: trunkSizes.fetch(projectID),
|
||||
sharedRequest: shared
|
||||
trunks: calculateTrunkDuctSizes(details: details, shared: shared)
|
||||
),
|
||||
shared,
|
||||
rooms
|
||||
shared
|
||||
)
|
||||
}
|
||||
|
||||
func calculateRoomDuctSizes(
|
||||
details: Project.Detail
|
||||
) async throws -> ([DuctSizes.RoomContainer], DuctSizeSharedRequest) {
|
||||
) async throws -> (rooms: [DuctSizes.RoomContainer], shared: DuctSizeSharedRequest) {
|
||||
@Dependency(\.manualD) var manualD
|
||||
|
||||
let shared = try sharedDuctRequest(details: details)
|
||||
@@ -42,54 +28,29 @@ extension DatabaseClient {
|
||||
return (rooms, shared)
|
||||
}
|
||||
|
||||
func calculateRoomDuctSizes(
|
||||
projectID: Project.ID
|
||||
) async throws -> ([DuctSizes.RoomContainer], DuctSizeSharedRequest) {
|
||||
func calculateTrunkDuctSizes(
|
||||
details: Project.Detail,
|
||||
shared: DuctSizeSharedRequest? = nil
|
||||
) async throws -> [DuctSizes.TrunkContainer] {
|
||||
@Dependency(\.manualD) var manualD
|
||||
|
||||
let shared = try await sharedDuctRequest(projectID)
|
||||
|
||||
return try await (
|
||||
manualD.calculateRoomSizes(
|
||||
rooms: rooms.fetch(projectID),
|
||||
sharedRequest: shared
|
||||
),
|
||||
shared
|
||||
)
|
||||
let sharedRequest: DuctSizeSharedRequest
|
||||
if let shared {
|
||||
sharedRequest = shared
|
||||
} else {
|
||||
sharedRequest = try sharedDuctRequest(details: details)
|
||||
}
|
||||
|
||||
func calculateTrunkDuctSizes(
|
||||
details: Project.Detail
|
||||
) async throws -> ([DuctSizes.TrunkContainer], DuctSizeSharedRequest) {
|
||||
@Dependency(\.manualD) var manualD
|
||||
|
||||
let shared = try sharedDuctRequest(details: details)
|
||||
let trunks = try await manualD.calculateTrunkSizes(
|
||||
return try await manualD.calculateTrunkSizes(
|
||||
rooms: details.rooms,
|
||||
trunks: details.trunks,
|
||||
sharedRequest: shared
|
||||
)
|
||||
return (trunks, shared)
|
||||
}
|
||||
|
||||
func calculateTrunkDuctSizes(
|
||||
projectID: Project.ID
|
||||
) async throws -> ([DuctSizes.TrunkContainer], DuctSizeSharedRequest) {
|
||||
@Dependency(\.manualD) var manualD
|
||||
|
||||
let shared = try await sharedDuctRequest(projectID)
|
||||
|
||||
return try await (
|
||||
manualD.calculateTrunkSizes(
|
||||
rooms: rooms.fetch(projectID),
|
||||
trunks: trunkSizes.fetch(projectID),
|
||||
sharedRequest: shared
|
||||
),
|
||||
shared
|
||||
sharedRequest: sharedRequest
|
||||
)
|
||||
}
|
||||
|
||||
func sharedDuctRequest(details: Project.Detail) throws -> DuctSizeSharedRequest {
|
||||
let projectSHR = try details.project.ensuredSHR()
|
||||
|
||||
guard
|
||||
let dfrResponse = designFrictionRate(
|
||||
componentLosses: details.componentLosses,
|
||||
@@ -100,10 +61,6 @@ extension DatabaseClient {
|
||||
throw ProjectClientError("Project not complete.")
|
||||
}
|
||||
|
||||
guard let projectSHR = details.project.sensibleHeatRatio else {
|
||||
throw ProjectClientError("Project sensible heat ratio not set.")
|
||||
}
|
||||
|
||||
let ensuredTEL = try dfrResponse.ensureMaxContainer()
|
||||
|
||||
return .init(
|
||||
@@ -115,32 +72,6 @@ extension DatabaseClient {
|
||||
)
|
||||
}
|
||||
|
||||
func sharedDuctRequest(_ projectID: Project.ID) async throws -> DuctSizeSharedRequest {
|
||||
|
||||
guard let dfrResponse = try await designFrictionRate(projectID: projectID) else {
|
||||
throw ProjectClientError("Project not complete.")
|
||||
}
|
||||
|
||||
let ensuredTEL = try dfrResponse.ensureMaxContainer()
|
||||
|
||||
return try await .init(
|
||||
equipmentInfo: dfrResponse.equipmentInfo,
|
||||
maxSupplyLength: ensuredTEL.supply,
|
||||
maxReturnLenght: ensuredTEL.return,
|
||||
designFrictionRate: dfrResponse.designFrictionRate,
|
||||
projectSHR: ensuredSHR(projectID)
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
// Fetches the project sensible heat ratio or throws an error if it's nil.
|
||||
func ensuredSHR(_ projectID: Project.ID) async throws -> Double {
|
||||
guard let projectSHR = try await projects.getSensibleHeatRatio(projectID) else {
|
||||
throw ProjectClientError("Project sensible heat ratio not set.")
|
||||
}
|
||||
return projectSHR
|
||||
}
|
||||
|
||||
// Internal container.
|
||||
struct DesignFrictionRateResponse: Equatable, Sendable {
|
||||
|
||||
@@ -183,18 +114,13 @@ extension DatabaseClient {
|
||||
|
||||
}
|
||||
|
||||
func designFrictionRate(
|
||||
projectID: Project.ID
|
||||
) async throws -> DesignFrictionRateResponse? {
|
||||
}
|
||||
|
||||
guard let equipmentInfo = try await equipment.fetch(projectID) else {
|
||||
return nil
|
||||
extension Project {
|
||||
func ensuredSHR() throws -> Double {
|
||||
guard let shr = sensibleHeatRatio else {
|
||||
throw ProjectClientError("Sensible heat ratio not set on project id: \(id)")
|
||||
}
|
||||
|
||||
return try await designFrictionRate(
|
||||
componentLosses: componentLosses.fetch(projectID),
|
||||
equipmentInfo: equipmentInfo,
|
||||
equivalentLengths: equivalentLengths.fetchMax(projectID)
|
||||
)
|
||||
return shr
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
import DatabaseClient
|
||||
import Dependencies
|
||||
import ManualDClient
|
||||
import ManualDCore
|
||||
import PdfClient
|
||||
|
||||
extension DatabaseClient {
|
||||
|
||||
/// Generate a pdf request for the given project.
|
||||
func makePdfRequest(_ projectID: Project.ID) async throws -> PdfClient.Request {
|
||||
@Dependency(\.manualD) var manualD
|
||||
|
||||
guard let projectDetails = try await projects.detail(projectID) else {
|
||||
throw ProjectClientError.notFound(.project(projectID))
|
||||
}
|
||||
|
||||
let (ductSizes, shared) = try await calculateDuctSizes(details: projectDetails)
|
||||
|
||||
let frictionRateResponse = try await manualD.frictionRate(details: projectDetails)
|
||||
guard let frictionRate = frictionRateResponse.frictionRate else {
|
||||
throw ProjectClientError.notFound(.frictionRate(projectID))
|
||||
}
|
||||
|
||||
return .init(
|
||||
details: projectDetails,
|
||||
ductSizes: ductSizes,
|
||||
shared: shared,
|
||||
frictionRate: frictionRate
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension PdfClient.Request {
|
||||
fileprivate init(
|
||||
details: Project.Detail,
|
||||
ductSizes: DuctSizes,
|
||||
shared: DuctSizeSharedRequest,
|
||||
frictionRate: FrictionRate
|
||||
) {
|
||||
self.init(
|
||||
project: details.project,
|
||||
rooms: details.rooms,
|
||||
componentLosses: details.componentLosses,
|
||||
ductSizes: ductSizes,
|
||||
equipmentInfo: details.equipmentInfo,
|
||||
maxSupplyTEL: shared.maxSupplyLength,
|
||||
maxReturnTEL: shared.maxReturnLenght,
|
||||
frictionRate: frictionRate,
|
||||
projectSHR: shared.projectSHR
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -15,14 +15,17 @@ extension ProjectClient: DependencyKey {
|
||||
@Dependency(\.fileClient) var fileClient
|
||||
|
||||
return .init(
|
||||
calculateDuctSizes: { projectID in
|
||||
try await database.calculateDuctSizes(projectID: projectID).0
|
||||
},
|
||||
calculateRoomDuctSizes: { projectID in
|
||||
try await database.calculateRoomDuctSizes(projectID: projectID).0
|
||||
guard let details = try await database.projects.detail(projectID) else {
|
||||
throw ProjectClientError.notFound(.project(projectID))
|
||||
}
|
||||
return try await database.calculateRoomDuctSizes(details: details).rooms
|
||||
},
|
||||
calculateTrunkDuctSizes: { projectID in
|
||||
try await database.calculateTrunkDuctSizes(projectID: projectID).0
|
||||
guard let details = try await database.projects.detail(projectID) else {
|
||||
throw ProjectClientError.notFound(.project(projectID))
|
||||
}
|
||||
return try await database.calculateTrunkDuctSizes(details: details)
|
||||
},
|
||||
createProject: { userID, request in
|
||||
let project = try await database.projects.create(userID, request)
|
||||
@@ -58,50 +61,3 @@ extension ProjectClient: DependencyKey {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension DatabaseClient {
|
||||
|
||||
fileprivate func makePdfRequest(_ projectID: Project.ID) async throws -> PdfClient.Request {
|
||||
@Dependency(\.manualD) var manualD
|
||||
|
||||
guard let projectDetails = try await projects.detail(projectID) else {
|
||||
throw ProjectClientError("Project not found. id: \(projectID)")
|
||||
}
|
||||
|
||||
let (ductSizes, shared) = try await calculateDuctSizes(details: projectDetails)
|
||||
|
||||
let frictionRateResponse = try await manualD.frictionRate(details: projectDetails)
|
||||
guard let frictionRate = frictionRateResponse.frictionRate else {
|
||||
throw ProjectClientError("Friction rate not found. id: \(projectID)")
|
||||
}
|
||||
|
||||
return .init(
|
||||
details: projectDetails,
|
||||
ductSizes: ductSizes,
|
||||
shared: shared,
|
||||
frictionRate: frictionRate
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension PdfClient.Request {
|
||||
init(
|
||||
details: Project.Detail,
|
||||
ductSizes: DuctSizes,
|
||||
shared: DuctSizeSharedRequest,
|
||||
frictionRate: FrictionRate
|
||||
) {
|
||||
self.init(
|
||||
project: details.project,
|
||||
rooms: details.rooms,
|
||||
componentLosses: details.componentLosses,
|
||||
ductSizes: ductSizes,
|
||||
equipmentInfo: details.equipmentInfo,
|
||||
maxSupplyTEL: shared.maxSupplyLength,
|
||||
maxReturnTEL: shared.maxReturnLenght,
|
||||
frictionRate: frictionRate,
|
||||
projectSHR: shared.projectSHR
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
35
Sources/ProjectClient/ProjectClientError.swift
Normal file
35
Sources/ProjectClient/ProjectClientError.swift
Normal file
@@ -0,0 +1,35 @@
|
||||
import Foundation
|
||||
import ManualDCore
|
||||
|
||||
public struct ProjectClientError: Error {
|
||||
public let reason: String
|
||||
|
||||
public init(_ reason: String) {
|
||||
self.reason = reason
|
||||
}
|
||||
|
||||
static func notFound(_ notFound: NotFound) -> Self {
|
||||
.init(notFound.reason)
|
||||
}
|
||||
|
||||
enum NotFound {
|
||||
case project(Project.ID)
|
||||
case frictionRate(Project.ID)
|
||||
|
||||
var reason: String {
|
||||
switch self {
|
||||
case .project(let id):
|
||||
return "Project not found. id: \(id)"
|
||||
case .frictionRate(let id):
|
||||
return """
|
||||
Friction unable to be calculated. id: \(id)
|
||||
|
||||
This usually means that not all the required steps have been completed.
|
||||
|
||||
Calculating the friction rate requires the component pressure losses to be set and
|
||||
have a max equivalent length for both the supply and return.
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
39
Tests/DatabaseClientTests/Helpers.swift
Normal file
39
Tests/DatabaseClientTests/Helpers.swift
Normal file
@@ -0,0 +1,39 @@
|
||||
import App
|
||||
import DatabaseClient
|
||||
import Dependencies
|
||||
import Fluent
|
||||
import FluentSQLiteDriver
|
||||
import Foundation
|
||||
import NIO
|
||||
import Vapor
|
||||
|
||||
// Helper to create an in-memory database for testing.
|
||||
func withDatabase(
|
||||
setupDependencies: (inout DependencyValues) -> Void = { _ in },
|
||||
operation: () async throws -> Void
|
||||
) async throws {
|
||||
let app = try await Application.make(.testing)
|
||||
do {
|
||||
try await configure(app)
|
||||
let database = app.db
|
||||
try await app.autoMigrate()
|
||||
|
||||
try await withDependencies {
|
||||
$0.uuid = .incrementing
|
||||
$0.date = .init { Date() }
|
||||
$0.database = .live(database: database)
|
||||
setupDependencies(&$0)
|
||||
} operation: {
|
||||
try await operation()
|
||||
}
|
||||
|
||||
try await app.autoRevert()
|
||||
try await app.asyncShutdown()
|
||||
|
||||
} catch {
|
||||
try? await app.autoRevert()
|
||||
try await app.asyncShutdown()
|
||||
throw error
|
||||
}
|
||||
|
||||
}
|
||||
29
Tests/DatabaseClientTests/ProjectTests.swift
Normal file
29
Tests/DatabaseClientTests/ProjectTests.swift
Normal file
@@ -0,0 +1,29 @@
|
||||
import Dependencies
|
||||
import DependenciesTestSupport
|
||||
import Fluent
|
||||
import FluentSQLiteDriver
|
||||
import ManualDCore
|
||||
import Testing
|
||||
import Vapor
|
||||
|
||||
@testable import DatabaseClient
|
||||
|
||||
@Suite
|
||||
struct ProjectTests {
|
||||
|
||||
@Test
|
||||
func sanity() {
|
||||
#expect(Bool(true))
|
||||
}
|
||||
|
||||
// @Test
|
||||
// func createProject() {
|
||||
// try await withDatabase(migrations: Project.Migrate()) {
|
||||
// $0.database.projects = .live(database: $1)
|
||||
// } operation: {
|
||||
// @Dependency(\.database.projects) var projects
|
||||
//
|
||||
// let project = try await projects.c
|
||||
// }
|
||||
// }
|
||||
}
|
||||
76
Tests/DatabaseClientTests/UserTests.swift
Normal file
76
Tests/DatabaseClientTests/UserTests.swift
Normal file
@@ -0,0 +1,76 @@
|
||||
import DatabaseClient
|
||||
import Dependencies
|
||||
import Foundation
|
||||
import ManualDCore
|
||||
import Testing
|
||||
|
||||
@testable import DatabaseClient
|
||||
|
||||
@Suite
|
||||
struct UserDatabaseTests {
|
||||
|
||||
@Test
|
||||
func createUser() async throws {
|
||||
try await withDatabase {
|
||||
@Dependency(\.database.users) var users
|
||||
|
||||
let user = try await users.create(
|
||||
.init(email: "testy@example.com", password: "super-secret", confirmPassword: "super-secret")
|
||||
)
|
||||
|
||||
#expect(user.email == "testy@example.com")
|
||||
|
||||
// Test login the user in
|
||||
let token = try await users.login(
|
||||
.init(email: "testy@example.com", password: "super-secret")
|
||||
)
|
||||
// Test logging out
|
||||
try await users.logout(token.id)
|
||||
|
||||
try await users.delete(user.id)
|
||||
|
||||
let shouldBeNilUser = try await users.get(user.id)
|
||||
#expect(shouldBeNilUser == nil)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
func createUserFails() async throws {
|
||||
try await withDatabase {
|
||||
@Dependency(\.database.users) var users
|
||||
|
||||
await #expect(throws: ValidationError.self) {
|
||||
try await users.create(.init(email: "", password: "", confirmPassword: ""))
|
||||
}
|
||||
|
||||
await #expect(throws: ValidationError.self) {
|
||||
try await users.create(.init(email: "testy@example.com", password: "", confirmPassword: ""))
|
||||
}
|
||||
|
||||
await #expect(throws: ValidationError.self) {
|
||||
try await users.create(
|
||||
.init(email: "testy@example.com", password: "super-secret", confirmPassword: ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
func deleteFailsWithInvalidUserID() async throws {
|
||||
try await withDatabase {
|
||||
@Dependency(\.database.users) var users
|
||||
await #expect(throws: NotFoundError.self) {
|
||||
try await users.delete(UUID(0))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
func logoutIgnoresUnfoundTokenID() async throws {
|
||||
try await withDatabase {
|
||||
@Dependency(\.database.users) var users
|
||||
try await users.logout(UUID(0))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -100,6 +100,12 @@ struct ViewControllerTests {
|
||||
)
|
||||
}
|
||||
|
||||
let mockDuctSizes = DuctSizes.mock(
|
||||
equipmentInfo: equipment,
|
||||
rooms: rooms,
|
||||
trunks: trunks
|
||||
)
|
||||
|
||||
try await withDefaultDependencies {
|
||||
$0.database.projects.get = { _ in project }
|
||||
$0.database.projects.getCompletedSteps = { _ in
|
||||
@@ -113,8 +119,11 @@ struct ViewControllerTests {
|
||||
.init(supply: tels.first, return: tels.last)
|
||||
}
|
||||
$0.database.componentLosses.fetch = { _ in componentLosses }
|
||||
$0.projectClient.calculateDuctSizes = { _ in
|
||||
.mock(equipmentInfo: equipment, rooms: rooms, trunks: trunks)
|
||||
$0.projectClient.calculateRoomDuctSizes = { _ in
|
||||
mockDuctSizes.rooms
|
||||
}
|
||||
$0.projectClient.calculateTrunkDuctSizes = { _ in
|
||||
mockDuctSizes.trunks
|
||||
}
|
||||
} operation: {
|
||||
@Dependency(\.viewController) var viewController
|
||||
|
||||
10
justfile
10
justfile
@@ -21,3 +21,13 @@ run-docker:
|
||||
|
||||
test-docker: (build-docker "docker/Dockerfile.test")
|
||||
@docker run --rm {{docker_image}}:{{docker_tag}} swift test
|
||||
|
||||
code-coverage:
|
||||
@llvm-cov report \
|
||||
"$(find $(swift build --show-bin-path) -name '*.xctest')" \
|
||||
-instr-profile=.build/debug/codecov/default.profdata \
|
||||
-ignore-filename-regex=".build|Tests" \
|
||||
-use-color
|
||||
|
||||
test:
|
||||
@swift test --enable-code-coverage
|
||||
|
||||
Reference in New Issue
Block a user