|
|
@@ -88,10 +88,10 @@ import Testing
|
|
|
// wholeCalc = round(wholeCobInsulin + correctionInsulin + fifteenMinutesInsulin - iobInsulinReduction, 3) = 11.125U
|
|
|
// insulinCalculated = round(wholeCalc × fraction, 3) = 8.9U
|
|
|
|
|
|
- // Calculate expected values with proper rounding using roundBolus method from the apsManager
|
|
|
- let wholeCobInsulin = apsManager.roundBolus(amount: Decimal(100) / Decimal(10)) // 10U
|
|
|
- let targetDifferenceInsulin = apsManager.roundBolus(amount: Decimal(80) / Decimal(40)) // 2U
|
|
|
- let fifteenMinutesInsulin = apsManager.roundBolus(amount: Decimal(5) / Decimal(40)) // 0.125U
|
|
|
+ // Calculate expected values
|
|
|
+ let wholeCobInsulin = Decimal(100) / Decimal(10) // 10U
|
|
|
+ let targetDifferenceInsulin = Decimal(80) / Decimal(40) // 2U
|
|
|
+ let fifteenMinutesInsulin = Decimal(5) / Decimal(40)
|
|
|
let wholeCalc = wholeCobInsulin + targetDifferenceInsulin + fifteenMinutesInsulin - Decimal(1) // 11.125U
|
|
|
let expectedInsulinCalculated = apsManager.roundBolus(amount: wholeCalc * fraction) // 8.9U
|
|
|
|
|
|
@@ -104,7 +104,6 @@ import Testing
|
|
|
Components from CalculationResult:
|
|
|
- insulinCalculated: \(result.insulinCalculated)U (expected: \(expectedInsulinCalculated)U)
|
|
|
- wholeCalc: \(result.wholeCalc)U (expected: \(wholeCalc)U)
|
|
|
- - correctionInsulin: \(result.correctionInsulin)U (expected: \(targetDifferenceInsulin)U)
|
|
|
- iobInsulinReduction: \(result.iobInsulinReduction)U (expected: 1U)
|
|
|
- superBolusInsulin: \(result.superBolusInsulin)U (expected: 0U)
|
|
|
- targetDifference: \(result.targetDifference) mg/dL (expected: 80 mg/dL)
|
|
|
@@ -121,10 +120,6 @@ import Testing
|
|
|
"Final calculated insulin amount should be \(expectedInsulinCalculated)U"
|
|
|
)
|
|
|
#expect(result.wholeCalc == wholeCalc, "Total calculation before fraction should be \(wholeCalc)U")
|
|
|
- #expect(
|
|
|
- result.correctionInsulin == targetDifferenceInsulin,
|
|
|
- "Insulin for BG correction should be \(targetDifferenceInsulin)U"
|
|
|
- )
|
|
|
#expect(result.iobInsulinReduction == -1.0, "Absolute IOB reduction amount should be 1U, hence -1U")
|
|
|
#expect(result.superBolusInsulin == 0, "Additional insulin for super bolus should be 0U")
|
|
|
#expect(result.targetDifference == 80, "Difference from target BG should be 80 mg/dL")
|
|
|
@@ -491,7 +486,8 @@ import Testing
|
|
|
useFattyMealCorrection: false,
|
|
|
useSuperBolus: false,
|
|
|
lastLoopDate: Date(),
|
|
|
- minPredBG: nil
|
|
|
+ minPredBG: nil,
|
|
|
+ simulatedCOB: nil
|
|
|
)
|
|
|
|
|
|
// Then
|
|
|
@@ -664,6 +660,124 @@ import Testing
|
|
|
fileStorage.save(originalISFValues, as: OpenAPS.Settings.insulinSensitivities)
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ @Test("Calculate insulin with backdated carbs") func testBackdatedCarbsCalculation() async throws {
|
|
|
+ // STEP 1: Setup test scenario
|
|
|
+ let currentDate = Date()
|
|
|
+ let backdatedCarbsDate = currentDate.addingTimeInterval(-60 * 60) // 1 hour ago
|
|
|
+
|
|
|
+ let currentBG: Decimal = 140
|
|
|
+ let target: Decimal = 100
|
|
|
+ let isf: Decimal = 40
|
|
|
+ let carbRatio: Decimal = 10
|
|
|
+ let iob: Decimal = 0.5
|
|
|
+ let cob: Int16 = 10 // Existing COB before adding backdated carbs
|
|
|
+ let carbs: Decimal = 30 // 30g of carbs, backdated 1 hour
|
|
|
+
|
|
|
+ // Get the COB value for the backdated carbs
|
|
|
+ // Use the actual APS Manager to calculate simulated COB for more realistic test
|
|
|
+ let determination = await apsManager.simulateDetermineBasal(
|
|
|
+ simulatedCarbsAmount: carbs,
|
|
|
+ simulatedBolusAmount: 0,
|
|
|
+ simulatedCarbsDate: backdatedCarbsDate
|
|
|
+ )
|
|
|
+
|
|
|
+ // Fallback to existing COB if determination is nil
|
|
|
+ let simulatedCOB = determination?.cob ?? Decimal(cob)
|
|
|
+
|
|
|
+ // For comparison - same scenario but with current time carbs
|
|
|
+ let currentTimeInput = CalculationInput(
|
|
|
+ carbs: carbs, // the newly entered carbs (30g)
|
|
|
+ currentBG: currentBG,
|
|
|
+ deltaBG: 0,
|
|
|
+ target: target,
|
|
|
+ isf: isf,
|
|
|
+ carbRatio: carbRatio,
|
|
|
+ iob: iob,
|
|
|
+ cob: cob, // the existing cob (10g)
|
|
|
+ useFattyMealCorrectionFactor: false,
|
|
|
+ fattyMealFactor: 0.8,
|
|
|
+ useSuperBolus: false,
|
|
|
+ sweetMealFactor: 1,
|
|
|
+ basal: 1.0,
|
|
|
+ fraction: 1.0,
|
|
|
+ maxBolus: 10,
|
|
|
+ maxIOB: 15,
|
|
|
+ maxCOB: 120,
|
|
|
+ minPredBG: 80,
|
|
|
+ lastLoopDate: currentDate
|
|
|
+ )
|
|
|
+
|
|
|
+ // Backdated scenario uses the same input but simulates date in the past
|
|
|
+ let backdatedInput = CalculationInput(
|
|
|
+ carbs: 0, // as the carbs are backdated we need to set the (newly entered) carbs to 0
|
|
|
+ currentBG: currentBG,
|
|
|
+ deltaBG: 0,
|
|
|
+ target: target,
|
|
|
+ isf: isf,
|
|
|
+ carbRatio: carbRatio,
|
|
|
+ iob: iob,
|
|
|
+ cob: Int16(truncating: NSDecimalNumber(decimal: simulatedCOB)), // current COB we got from the simulated Determination
|
|
|
+ useFattyMealCorrectionFactor: false,
|
|
|
+ fattyMealFactor: 0.8,
|
|
|
+ useSuperBolus: false,
|
|
|
+ sweetMealFactor: 1,
|
|
|
+ basal: 1.0,
|
|
|
+ fraction: 1.0,
|
|
|
+ maxBolus: 10,
|
|
|
+ maxIOB: 15,
|
|
|
+ maxCOB: 120,
|
|
|
+ minPredBG: 80,
|
|
|
+ lastLoopDate: currentDate
|
|
|
+ )
|
|
|
+
|
|
|
+ // STEP 2: Calculate insulin for both scenarios
|
|
|
+ let currentTimeResult = await calculator.calculateInsulin(input: currentTimeInput)
|
|
|
+ let backdatedResult = await calculator.calculateInsulin(input: backdatedInput)
|
|
|
+
|
|
|
+ // STEP 3: Verify results
|
|
|
+
|
|
|
+ // In the current time scenario, we expect COB to be old COB + current carbs
|
|
|
+ let expectedCurrentTimeCOB = Decimal(cob) + carbs
|
|
|
+ #expect(
|
|
|
+ currentTimeResult.wholeCob == expectedCurrentTimeCOB,
|
|
|
+ "Current time scenario should have \(expectedCurrentTimeCOB)g COB (\(cob)g existing + \(carbs)g new)"
|
|
|
+ )
|
|
|
+
|
|
|
+ // For backdated scenario, COB should be less than the current time scenario
|
|
|
+ // because some carbs have already been absorbed
|
|
|
+ #expect(
|
|
|
+ backdatedResult.wholeCob < currentTimeResult.wholeCob,
|
|
|
+ """
|
|
|
+ Backdated scenario should have less COB than current time scenario
|
|
|
+ Backdated: \(backdatedResult.wholeCob)g
|
|
|
+ Current time: \(currentTimeResult.wholeCob)g
|
|
|
+ Difference: \(currentTimeResult.wholeCob - backdatedResult.wholeCob)g
|
|
|
+ """
|
|
|
+ )
|
|
|
+
|
|
|
+ // The wholeCobInsulin should reflect the difference in COB
|
|
|
+ #expect(
|
|
|
+ backdatedResult.wholeCobInsulin < currentTimeResult.wholeCobInsulin,
|
|
|
+ """
|
|
|
+ Backdated scenario should require less insulin for carbs due to partial absorption
|
|
|
+ Backdated insulin: \(backdatedResult.wholeCobInsulin)U
|
|
|
+ Current time insulin: \(currentTimeResult.wholeCobInsulin)U
|
|
|
+ Difference: \(currentTimeResult.wholeCobInsulin - backdatedResult.wholeCobInsulin)U
|
|
|
+ """
|
|
|
+ )
|
|
|
+
|
|
|
+ // The backdated scenario should recommend less insulin than the current time scenario
|
|
|
+ #expect(
|
|
|
+ backdatedResult.insulinCalculated < currentTimeResult.insulinCalculated,
|
|
|
+ """
|
|
|
+ Backdated carbs should result in lower insulin recommendation
|
|
|
+ Current time: \(currentTimeResult.insulinCalculated)U
|
|
|
+ Backdated: \(backdatedResult.insulinCalculated)U
|
|
|
+ Difference: \(currentTimeResult.insulinCalculated - backdatedResult.insulinCalculated)U
|
|
|
+ """
|
|
|
+ )
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// Copied over from BolusCalculationManager as they are not included in the protocol definition (and I don´t want them to be included)
|