feat: Adds project database tests.
All checks were successful
CI / Linux Tests (push) Successful in 5m24s

This commit is contained in:
2026-01-30 14:02:58 -05:00
parent c32ffcff8c
commit a51e1b34d0
7 changed files with 297 additions and 73 deletions

View File

@@ -4,10 +4,11 @@ import Dependencies
import Fluent
import FluentSQLiteDriver
import Foundation
import ManualDCore
import NIO
import Vapor
// Helper to create an in-memory database for testing.
// Helper to create an in-memory database used for testing.
func withDatabase(
setupDependencies: (inout DependencyValues) -> Void = { _ in },
operation: () async throws -> Void
@@ -37,3 +38,18 @@ func withDatabase(
}
}
/// Set's up the database and a test user for running tests that require a
/// a user.
func withTestUser(
setupDependencies: (inout DependencyValues) -> Void = { _ in },
operation: (User) async throws -> Void
) async throws {
try await withDatabase(setupDependencies: setupDependencies) {
@Dependency(\.database.users) var users
let user = try await users.create(
.init(email: "testy@example.com", password: "super-secret", confirmPassword: "super-secret")
)
try await operation(user)
}
}

View File

@@ -12,18 +12,155 @@ import Vapor
struct ProjectTests {
@Test
func sanity() {
#expect(Bool(true))
func projectHappyPaths() async throws {
try await withTestUser { user in
@Dependency(\.database.projects) var projects
let project = try await projects.create(user.id, .mock)
let got = try await projects.get(project.id)
#expect(got == project)
let page = try await projects.fetch(user.id, .init(page: 1, per: 25))
#expect(page.items.first! == project)
let updated = try await projects.update(project.id, .init(sensibleHeatRatio: 0.83))
#expect(updated.sensibleHeatRatio == 0.83)
#expect(updated.id == project.id)
let shr = try await projects.getSensibleHeatRatio(project.id)
#expect(shr == 0.83)
try await projects.delete(project.id)
}
}
@Test
func notFound() async throws {
try await withDatabase {
@Dependency(\.database.projects) var projects
await #expect(throws: NotFoundError.self) {
try await projects.delete(UUID(0))
}
await #expect(throws: NotFoundError.self) {
try await projects.update(UUID(0), .init(name: "Foo"))
}
await #expect(throws: NotFoundError.self) {
try await projects.getSensibleHeatRatio(UUID(0))
}
await #expect(throws: NotFoundError.self) {
try await projects.getCompletedSteps(UUID(0))
}
}
}
@Test
func completedSteps() async throws {
try await withTestUser { user in
@Dependency(\.database) var database
let project = try await database.projects.create(user.id, .mock)
var completed = try await database.projects.getCompletedSteps(project.id)
#expect(completed.equipmentInfo == false)
#expect(completed.equivalentLength == false)
#expect(completed.frictionRate == false)
#expect(completed.rooms == false)
_ = try await database.equipment.create(
.init(projectID: project.id, heatingCFM: 1000, coolingCFM: 1000)
)
completed = try await database.projects.getCompletedSteps(project.id)
#expect(completed.equipmentInfo == true)
_ = try await database.componentLosses.create(
.init(projectID: project.id, name: "Test", value: 0.2)
)
completed = try await database.projects.getCompletedSteps(project.id)
#expect(completed.frictionRate == true)
_ = try await database.rooms.create(
.init(projectID: project.id, name: "Test", heatingLoad: 12345, coolingTotal: 12345)
)
completed = try await database.projects.getCompletedSteps(project.id)
#expect(completed.rooms == true)
_ = try await database.equivalentLengths.create(
.init(
projectID: project.id, name: "Supply", type: .supply, straightLengths: [1], groups: [])
)
completed = try await database.projects.getCompletedSteps(project.id)
// Should not be complete until we have both return and supply for a project.
#expect(completed.equivalentLength == false)
_ = try await database.equivalentLengths.create(
.init(
projectID: project.id, name: "Return", type: .return, straightLengths: [1], groups: [])
)
completed = try await database.projects.getCompletedSteps(project.id)
#expect(completed.equipmentInfo == true)
#expect(completed.equivalentLength == true)
#expect(completed.frictionRate == true)
#expect(completed.rooms == true)
}
}
@Test
func detail() async throws {
try await withTestUser { user in
@Dependency(\.database) var database
let project = try await database.projects.create(user.id, .mock)
var detail = try await database.projects.detail(project.id)
#expect(detail == nil)
let equipment = try await database.equipment.create(
.init(projectID: project.id, heatingCFM: 1000, coolingCFM: 1000)
)
detail = try await database.projects.detail(project.id)
#expect(detail != nil)
let componentLoss = try await database.componentLosses.create(
.init(projectID: project.id, name: "Test", value: 0.2)
)
let room = try await database.rooms.create(
.init(projectID: project.id, name: "Test", heatingLoad: 12345, coolingTotal: 12345)
)
let supplyLength = try await database.equivalentLengths.create(
.init(
projectID: project.id, name: "Supply", type: .supply, straightLengths: [1], groups: [])
)
let returnLength = try await database.equivalentLengths.create(
.init(
projectID: project.id, name: "Return", type: .return, straightLengths: [1], groups: [])
)
detail = try await database.projects.detail(project.id)
#expect(detail?.componentLosses == [componentLoss])
#expect(detail?.equipmentInfo == equipment)
#expect(detail?.rooms == [room])
#expect(detail?.equivalentLengths.contains(supplyLength) == true)
#expect(detail?.equivalentLengths.contains(returnLength) == 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
// }
// }
}
extension Project.Create {
static let mock = Self(
name: "Testy McTestface",
streetAddress: "1234 Sesame St",
city: "Nowhere",
state: "MN",
zipCode: "55555",
sensibleHeatRatio: 0.83
)
}

View File

@@ -3,6 +3,7 @@ import Dependencies
import Foundation
import ManualDCore
import Testing
import Vapor
@testable import DatabaseClient
@@ -10,7 +11,7 @@ import Testing
struct UserDatabaseTests {
@Test
func createUser() async throws {
func happyPaths() async throws {
try await withDatabase {
@Dependency(\.database.users) var users
@@ -22,8 +23,14 @@ struct UserDatabaseTests {
// Test login the user in
let token = try await users.login(
.init(email: "testy@example.com", password: "super-secret")
.init(email: user.email, password: "super-secret")
)
#expect(token.userID == user.id)
// Test the same token is returned.
let token2 = try await users.login(
.init(email: user.email, password: "super-secret")
)
#expect(token.id == token2.id)
// Test logging out
try await users.logout(token.id)
@@ -31,7 +38,6 @@ struct UserDatabaseTests {
let shouldBeNilUser = try await users.get(user.id)
#expect(shouldBeNilUser == nil)
}
}
@@ -73,4 +79,73 @@ struct UserDatabaseTests {
}
}
@Test
func loginFails() async throws {
try await withDatabase {
@Dependency(\.database.users) var users
await #expect(throws: NotFoundError.self) {
try await users.login(
.init(email: "foo@example.com", password: "super-secret")
)
}
let user = try await users.create(
.init(email: "testy@example.com", password: "super-secret", confirmPassword: "super-secret")
)
// Ensure can not login with invalid password
await #expect(throws: Abort.self) {
try await users.login(
.init(email: user.email, password: "wrong-password")
)
}
}
}
@Test
func userProfileHappyPath() async throws {
try await withTestUser { user in
@Dependency(\.database.userProfiles) var profiles
let profile = try await profiles.create(
.init(
userID: user.id,
firstName: "Testy",
lastName: "McTestface",
companyName: "Acme Co.",
streetAddress: "12345 Sesame St",
city: "Nowhere",
state: "FL",
zipCode: "55555"
)
)
let fetched = try await profiles.fetch(user.id)
#expect(fetched == profile)
let got = try await profiles.get(profile.id)
#expect(got == profile)
let updated = try await profiles.update(profile.id, .init(firstName: "Updated"))
#expect(updated.firstName == "Updated")
#expect(updated.id == profile.id)
try await profiles.delete(profile.id)
}
}
@Test
func testUserProfileFails() async throws {
try await withDatabase {
@Dependency(\.database.userProfiles) var profiles
await #expect(throws: NotFoundError.self) {
try await profiles.delete(UUID(0))
}
await #expect(throws: NotFoundError.self) {
try await profiles.update(UUID(0), .init(firstName: "Foo"))
}
}
}
}