feat: working on tests for pressure estimation feature to resolve filter drop bugs
This commit is contained in:
@@ -5,6 +5,7 @@ import SharedModels
|
|||||||
import Styleguide
|
import Styleguide
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
|
#warning("Revert rated static pressures section.")
|
||||||
@Reducer
|
@Reducer
|
||||||
public struct EquipmentSettingsForm {
|
public struct EquipmentSettingsForm {
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ public struct FlaggedMeasurementsList: Sendable {
|
|||||||
|
|
||||||
@ObservableState
|
@ObservableState
|
||||||
@dynamicMemberLookup
|
@dynamicMemberLookup
|
||||||
public struct State: Equatable {
|
public struct State: Equatable, Sendable {
|
||||||
|
|
||||||
@Presents public var destination: Destination.State?
|
@Presents public var destination: Destination.State?
|
||||||
@Shared var sharedSettings: SharedPressureEstimationState
|
@Shared var sharedSettings: SharedPressureEstimationState
|
||||||
@@ -130,16 +130,38 @@ public struct FlaggedMeasurementsList: Sendable {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
state.destination = nil
|
state.destination = nil
|
||||||
return handleEstimationForm(form: form, state: state)
|
return .run { [state] send in
|
||||||
|
do {
|
||||||
|
guard let flaggedEstimation = try await self._handleEstimationForm(form: form, state: state)
|
||||||
|
else { return }
|
||||||
|
await send(.receive(.success(.estimatedFlaggedMeasurement(flaggedEstimation))))
|
||||||
|
} catch {
|
||||||
|
await send(.receive(.failure(error)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case .editButtonTapped(id: _):
|
case .editButtonTapped(id: _):
|
||||||
return .none
|
return .none
|
||||||
|
|
||||||
case .onAppear:
|
case .onAppear:
|
||||||
guard let equipmentMeasurement = state.sharedSettings.equipmentMeasurement else {
|
guard state.sharedSettings.flaggedEquipmentMeasurement == nil
|
||||||
return .none
|
else { return .none }
|
||||||
|
|
||||||
|
guard let equipmentMeasurement = state.sharedSettings.equipmentMeasurement
|
||||||
|
else {
|
||||||
|
return .fail(
|
||||||
|
"""
|
||||||
|
Equipment measurement is not set, skipping generating flagged measurement for existing
|
||||||
|
equipment.
|
||||||
|
|
||||||
|
This is considered an application logic error.
|
||||||
|
""",
|
||||||
|
logger: logger
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if state.sharedSettings.budgets == nil {
|
if state.sharedSettings.budgets == nil {
|
||||||
state.sharedSettings.budgets = .init(
|
state.sharedSettings.budgets = .init(
|
||||||
equipmentType: state.sharedSettings.equipmentMeasurement!.equipmentType,
|
equipmentType: state.sharedSettings.equipmentMeasurement!.equipmentType,
|
||||||
@@ -159,6 +181,42 @@ public struct FlaggedMeasurementsList: Sendable {
|
|||||||
.ifLet(\.$destination, action: \.destination)
|
.ifLet(\.$destination, action: \.destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum EstimationFormFailure: Error {
|
||||||
|
case invalidState
|
||||||
|
}
|
||||||
|
|
||||||
|
func _handleEstimationForm(form: EstimationForm.State, state: State) async throws -> SharedPressureEstimationState.FlaggedEstimationContainer? {
|
||||||
|
guard let equipmentMeasurement = state.sharedSettings.equipmentMeasurement,
|
||||||
|
let budgets = state.sharedSettings.budgets
|
||||||
|
else {
|
||||||
|
throw EstimationFormFailure.invalidState
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let estimationState = ensureHasChanges(
|
||||||
|
formState: form,
|
||||||
|
flaggedEstimations: state.sharedSettings.flaggedEstimations
|
||||||
|
) else {
|
||||||
|
logger.debug("No changes found, not generating a new flagged estimation measurement.")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
let flaggedMeasurement = try await flaggedMeasurement(
|
||||||
|
airflow: estimationState.cfm.airflow,
|
||||||
|
budgets: budgets,
|
||||||
|
equipmentMeasurement: equipmentMeasurement,
|
||||||
|
filterPressureDrop: parseFilterPressureDrop(formState: form, sharedSettings: state.sharedSettings),
|
||||||
|
ratedStaticPresures: state.sharedSettings.ratedStaticPressures,
|
||||||
|
tons: form.coolingCapacity
|
||||||
|
)
|
||||||
|
|
||||||
|
return SharedPressureEstimationState.FlaggedEstimationContainer(
|
||||||
|
id: form.id ?? uuid(),
|
||||||
|
estimationState: estimationState,
|
||||||
|
flaggedMeasurement: flaggedMeasurement
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#warning("This is making it hard to test, perhaps don't return an effect here.")
|
||||||
private func handleEstimationForm(form: EstimationForm.State, state: State) -> Effect<Action> {
|
private func handleEstimationForm(form: EstimationForm.State, state: State) -> Effect<Action> {
|
||||||
guard let equipmentMeasurement = state.sharedSettings.equipmentMeasurement,
|
guard let equipmentMeasurement = state.sharedSettings.equipmentMeasurement,
|
||||||
let budgets = state.sharedSettings.budgets
|
let budgets = state.sharedSettings.budgets
|
||||||
@@ -179,7 +237,6 @@ public struct FlaggedMeasurementsList: Sendable {
|
|||||||
flaggedEstimations: state.sharedSettings.flaggedEstimations
|
flaggedEstimations: state.sharedSettings.flaggedEstimations
|
||||||
) else {
|
) else {
|
||||||
logger.debug("No changes found, not generating a new flagged estimation measurement.")
|
logger.debug("No changes found, not generating a new flagged estimation measurement.")
|
||||||
print("No changes found, not generating a new flagged estimation measurement.")
|
|
||||||
return .none
|
return .none
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import ComposableArchitecture
|
import ComposableArchitecture
|
||||||
|
import SharedModels
|
||||||
import Testing
|
import Testing
|
||||||
|
import XCTest
|
||||||
@testable import PressureEstimationsFeature
|
@testable import PressureEstimationsFeature
|
||||||
|
|
||||||
struct FlaggedMeasurementListTests {
|
struct FlaggedMeasurementListStateTests {
|
||||||
|
|
||||||
@Test(
|
@Test(
|
||||||
"Ensure Estimation Has Changes",
|
"Ensure Estimation Has Changes",
|
||||||
@@ -21,6 +23,156 @@ struct FlaggedMeasurementListTests {
|
|||||||
#expect(result != nil)
|
#expect(result != nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(
|
||||||
|
"Handle Estimation Form",
|
||||||
|
.tags(.flaggedMeasurementList)
|
||||||
|
)
|
||||||
|
func handleEstimationForm() async throws {
|
||||||
|
try await withDependencies {
|
||||||
|
$0.estimatedPressuresClient = .liveValue
|
||||||
|
$0.uuid = .incrementing
|
||||||
|
} operation: {
|
||||||
|
@Dependency(\.estimatedPressuresClient) var client
|
||||||
|
|
||||||
|
let reducer = FlaggedMeasurementsList()
|
||||||
|
let result = try await reducer._handleEstimationForm(
|
||||||
|
form: .init(
|
||||||
|
existingMeasurement: SharedReader(Shared(.mock(type: .airHandler))),
|
||||||
|
cfmTextField: 350,
|
||||||
|
name: "Test"
|
||||||
|
),
|
||||||
|
state: .init(sharedSettings: Shared(.init(
|
||||||
|
budgets: .init(equipmentType: .airHandler, fanType: .constantSpeed),
|
||||||
|
equipmentMeasurement: .mock(type: .airHandler),
|
||||||
|
flaggedEquipmentMeasurement: .init(
|
||||||
|
budgets: .init(equipmentType: .airHandler, fanType: .constantSpeed),
|
||||||
|
measurement: .mock(type: .airHandler),
|
||||||
|
ratedPressures: .init(),
|
||||||
|
tons: .three
|
||||||
|
)
|
||||||
|
)))
|
||||||
|
)
|
||||||
|
|
||||||
|
let measurement = try await client.estimatedPressure(
|
||||||
|
equipmentMeasurement: .mock(type: .airHandler),
|
||||||
|
airflow: 1050,
|
||||||
|
filterPressureDrop: 0.1
|
||||||
|
)
|
||||||
|
|
||||||
|
#expect(result != nil)
|
||||||
|
#expect(result?.estimationState == .init(
|
||||||
|
cfm: .cfmPerTon(350, .three),
|
||||||
|
filterPressureDrop: 0.1,
|
||||||
|
name: "Test"
|
||||||
|
))
|
||||||
|
|
||||||
|
#expect(result?.flaggedMeasurement == .init(
|
||||||
|
budgets: .init(equipmentType: .airHandler, fanType: .constantSpeed),
|
||||||
|
measurement: measurement,
|
||||||
|
ratedPressures: .init(),
|
||||||
|
tons: .three)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
final class FlaggedMeasurementListReducerTests: XCTestCase {
|
||||||
|
|
||||||
|
override func invokeTest() {
|
||||||
|
withDependencies {
|
||||||
|
$0.uuid = .incrementing
|
||||||
|
$0.estimatedPressuresClient = .liveValue
|
||||||
|
} operation: {
|
||||||
|
super.invokeTest()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
func testFlaggedMeasurementListReducer() async throws {
|
||||||
|
@Dependency(\.estimatedPressuresClient) var estimatedPressuresClient
|
||||||
|
|
||||||
|
let store = TestStore(
|
||||||
|
initialState: FlaggedMeasurementsList.State(
|
||||||
|
sharedSettings: Shared(SharedPressureEstimationState(
|
||||||
|
budgets: nil,
|
||||||
|
equipmentMeasurement: .mock(type: .airHandler),
|
||||||
|
equipmentMetadata: .init(
|
||||||
|
coolingCapacity: .three,
|
||||||
|
fanType: .constantSpeed,
|
||||||
|
ratedStaticPressures: .init()
|
||||||
|
)
|
||||||
|
))
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
FlaggedMeasurementsList()
|
||||||
|
}
|
||||||
|
|
||||||
|
let budgets = BudgetedPercentEnvelope(
|
||||||
|
equipmentType: .airHandler,
|
||||||
|
fanType: .constantSpeed
|
||||||
|
)
|
||||||
|
|
||||||
|
let flaggedMeasurement = EquipmentMeasurement.FlaggedMeasurement.init(
|
||||||
|
budgets: budgets,
|
||||||
|
measurement: .mock(type: .airHandler),
|
||||||
|
ratedPressures: .init(),
|
||||||
|
tons: .three
|
||||||
|
)
|
||||||
|
|
||||||
|
await store.send(.view(.onAppear)) {
|
||||||
|
$0.sharedSettings.budgets = budgets
|
||||||
|
$0.sharedSettings.flaggedEquipmentMeasurement = flaggedMeasurement
|
||||||
|
}
|
||||||
|
|
||||||
|
await store.send(.view(.addButtonTapped)) {
|
||||||
|
$0.destination = .estimationForm(.init(
|
||||||
|
existingMeasurement: $0.$sharedSettings.equipmentMeasurement,
|
||||||
|
coolingCapacity: $0.sharedSettings.equipmentMetadata.coolingCapacity
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
store.exhaustivity = .off
|
||||||
|
|
||||||
|
await store.send(.destination(.presented(.estimationForm(.binding(.set(\.cfmTextField, 350))))))
|
||||||
|
await store.send(.destination(.presented(.estimationForm(.binding(.set(\.name, "Test"))))))
|
||||||
|
await store.send(.destination(.presented(.estimationForm(.binding(.set(\.filterPressureDrop, 0.1))))))
|
||||||
|
|
||||||
|
// store.exhaustivity = .on
|
||||||
|
let pressureResult = try await estimatedPressuresClient.estimatedPressure(
|
||||||
|
equipmentMeasurement: .mock(type: .airHandler),
|
||||||
|
airflow: 1050,
|
||||||
|
filterPressureDrop: 0.1
|
||||||
|
)
|
||||||
|
let flaggedResult = EquipmentMeasurement.FlaggedMeasurement(
|
||||||
|
budgets: budgets,
|
||||||
|
measurement: pressureResult,
|
||||||
|
ratedPressures: .init(),
|
||||||
|
tons: .three
|
||||||
|
)
|
||||||
|
|
||||||
|
store.exhaustivity = .off(showSkippedAssertions: true)
|
||||||
|
// store.exhaustivity = .on
|
||||||
|
|
||||||
|
await store.send(.view(.destination(.doneButtonTapped))) {
|
||||||
|
$0.destination = nil
|
||||||
|
}
|
||||||
|
// await store.receive(\.receive.failure, timeout: 10)
|
||||||
|
// await store.receive(\.receive.success.estimatedFlaggedMeasurement, timeout: 10) {
|
||||||
|
// $0.sharedSettings.flaggedEstimations[id: UUID(0)] = .init(
|
||||||
|
// id: UUID(0),
|
||||||
|
// estimationState: .init(
|
||||||
|
// cfm: .cfmPerTon(350, .three),
|
||||||
|
// filterPressureDrop: 0.1,
|
||||||
|
// name: "Test"
|
||||||
|
// ),
|
||||||
|
// flaggedMeasurement: flaggedResult
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
await store.finish()
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Tag {
|
extension Tag {
|
||||||
|
|||||||
Reference in New Issue
Block a user