Просмотр исходного кода

Rename enable SMB tests; add calculateExpectedDelta unit tests

Deniz Cengiz 11 месяцев назад
Родитель
Сommit
8494016993

+ 8 - 4
Trio.xcodeproj/project.pbxproj

@@ -634,7 +634,8 @@
 		DD30B9CA2E062A3400DA677C /* ForecastGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD30B9C92E062A3300DA677C /* ForecastGenerator.swift */; };
 		DD30B9CC2E062A7000DA677C /* ForecastResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD30B9CB2E062A7000DA677C /* ForecastResult.swift */; };
 		DD30B9CE2E062AA300DA677C /* SingleForecasting.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD30B9CD2E062AA300DA677C /* SingleForecasting.swift */; };
-		DD30B9FE2E0742E200DA677C /* SMBEnablementTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD30B9FD2E0742E200DA677C /* SMBEnablementTests.swift */; };
+		DD30B9FE2E0742E200DA677C /* DetermineBasalSMBEnablementTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD30B9FD2E0742E200DA677C /* DetermineBasalSMBEnablementTests.swift */; };
+		DD30BA002E0745C400DA677C /* DetermineBasalDeltaCalculationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD30B9FF2E0745C400DA677C /* DetermineBasalDeltaCalculationTests.swift */; };
 		DD32CF982CC82463003686D6 /* TrioRemoteControl+Bolus.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD32CF972CC82460003686D6 /* TrioRemoteControl+Bolus.swift */; };
 		DD32CF9A2CC8247B003686D6 /* TrioRemoteControl+Meal.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD32CF992CC8246F003686D6 /* TrioRemoteControl+Meal.swift */; };
 		DD32CF9C2CC82499003686D6 /* TrioRemoteControl+TempTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD32CF9B2CC82495003686D6 /* TrioRemoteControl+TempTarget.swift */; };
@@ -1540,7 +1541,8 @@
 		DD30B9C92E062A3300DA677C /* ForecastGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForecastGenerator.swift; sourceTree = "<group>"; };
 		DD30B9CB2E062A7000DA677C /* ForecastResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForecastResult.swift; sourceTree = "<group>"; };
 		DD30B9CD2E062AA300DA677C /* SingleForecasting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleForecasting.swift; sourceTree = "<group>"; };
-		DD30B9FD2E0742E200DA677C /* SMBEnablementTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SMBEnablementTests.swift; sourceTree = "<group>"; };
+		DD30B9FD2E0742E200DA677C /* DetermineBasalSMBEnablementTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetermineBasalSMBEnablementTests.swift; sourceTree = "<group>"; };
+		DD30B9FF2E0745C400DA677C /* DetermineBasalDeltaCalculationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetermineBasalDeltaCalculationTests.swift; sourceTree = "<group>"; };
 		DD32CF972CC82460003686D6 /* TrioRemoteControl+Bolus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TrioRemoteControl+Bolus.swift"; sourceTree = "<group>"; };
 		DD32CF992CC8246F003686D6 /* TrioRemoteControl+Meal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TrioRemoteControl+Meal.swift"; sourceTree = "<group>"; };
 		DD32CF9B2CC82495003686D6 /* TrioRemoteControl+TempTarget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TrioRemoteControl+TempTarget.swift"; sourceTree = "<group>"; };
@@ -2870,7 +2872,8 @@
 		3B5CD2C72D4AECD500CE213C /* OpenAPSSwiftTests */ = {
 			isa = PBXGroup;
 			children = (
-				DD30B9FD2E0742E200DA677C /* SMBEnablementTests.swift */,
+				DD30B9FF2E0745C400DA677C /* DetermineBasalDeltaCalculationTests.swift */,
+				DD30B9FD2E0742E200DA677C /* DetermineBasalSMBEnablementTests.swift */,
 				3BF92F2C2D86DEE9006B545A /* javascript */,
 				3B1C5C3C2D68E269004E9273 /* json */,
 				3BFA5BF72D989F380072B082 /* mocks */,
@@ -5119,7 +5122,7 @@
 				3BF8D14B2D530397001B3F84 /* JSONCompareTests.swift in Sources */,
 				3BEF6AB32D97316F0076089D /* MealTotalTests.swift in Sources */,
 				3BF8D0C12D5175BE001B3F84 /* ProfileJsNativeCompareTests.swift in Sources */,
-				DD30B9FE2E0742E200DA677C /* SMBEnablementTests.swift in Sources */,
+				DD30B9FE2E0742E200DA677C /* DetermineBasalSMBEnablementTests.swift in Sources */,
 				3BEF6AB12D9731660076089D /* MealHistoryTests.swift in Sources */,
 				BD8FC0572D66188700B95AED /* PumpHistoryStorageTests.swift in Sources */,
 				BD8FC0642D6619EF00B95AED /* TempTargetStorageTests.swift in Sources */,
@@ -5148,6 +5151,7 @@
 				3BEF6AB72D9750780076089D /* MealJsonTests.swift in Sources */,
 				38FCF3F925E902C20078B0D1 /* FileStorageTests.swift in Sources */,
 				BD8FC0602D6619DB00B95AED /* CarbsStorageTests.swift in Sources */,
+				DD30BA002E0745C400DA677C /* DetermineBasalDeltaCalculationTests.swift in Sources */,
 				BD8FC05E2D6618CE00B95AED /* BolusCalculatorTests.swift in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;

+ 1 - 1
Trio/Sources/APS/OpenAPSSwift/DetermineBasal/DetermineBasalGenerator.swift

@@ -78,7 +78,7 @@ extension DeterminationGenerator {
 
         let fiveMinuteBlocks = (2 * 60) / 5
         let delta = targetGlucose - eventualGlucose
-        return glucoseImpact + Decimal(Int(delta) / fiveMinuteBlocks).rounded(toPlaces: 1)
+        return (glucoseImpact + Decimal(Int(delta) / fiveMinuteBlocks)).rounded(toPlaces: 1)
     }
 
     /// Determines whether SMBs are enabled based on profile settings,

+ 104 - 0
TrioTests/OpenAPSSwiftTests/DetermineBasalDeltaCalculationTests.swift

@@ -0,0 +1,104 @@
+import Foundation
+import Testing
+@testable import Trio
+
+@Suite("Determination: Expected Delta Calculation Tests") struct ExpectedDeltaTests {
+    /// When delta is smaller than one 5-min block, only glucoseImpact is returned.
+    @Test("no change when delta < 24 blocks") func deltaSmallerThanBlock() {
+        let result = DeterminationGenerator.calculateExpectedDelta(
+            targetGlucose: Decimal(120),
+            eventualGlucose: Decimal(100),
+            glucoseImpact: Decimal(2)
+        )
+        // delta = 20; Int(20)/24 = 0 → result = 2 + 0 = 2.0
+        #expect(result == Decimal(2.0))
+    }
+
+    /// When delta spans exactly one block, adds 1 to glucoseImpact.
+    @Test("one block delta") func deltaExactlyOneBlock() {
+        let result = DeterminationGenerator.calculateExpectedDelta(
+            targetGlucose: Decimal(124),
+            eventualGlucose: Decimal(100),
+            glucoseImpact: Decimal(1.5)
+        )
+        // delta = 24; Int(24)/24 = 1 → result = 1.5 + 1 = 2.5
+        #expect(result == Decimal(2.5))
+    }
+
+    /// When delta spans multiple blocks, uses integer division.
+    @Test("multi-block delta") func deltaMultipleBlocks() {
+        let result = DeterminationGenerator.calculateExpectedDelta(
+            targetGlucose: Decimal(140),
+            eventualGlucose: Decimal(100),
+            glucoseImpact: Decimal(0)
+        )
+        // delta = 40; Int(40)/24 = 1 → result = 0 + 1 = 1.0
+        #expect(result == Decimal(1.0))
+    }
+
+    /// Negative delta yields negative adjustment when blocks exceed delta.
+    @Test("negative delta") func negativeDelta() {
+        let result = DeterminationGenerator.calculateExpectedDelta(
+            targetGlucose: Decimal(80),
+            eventualGlucose: Decimal(100),
+            glucoseImpact: Decimal(0)
+        )
+        // delta = -20; Int(-20)/24 = 0 (trunc toward zero) → result = 0 + 0 = 0.0
+        #expect(result == Decimal(0.0))
+    }
+
+    /// Fractional delta is truncated before block division.
+    @Test("fractional delta truncation") func fractionalDelta() {
+        let result = DeterminationGenerator.calculateExpectedDelta(
+            targetGlucose: Decimal(string: "125.5")!,
+            eventualGlucose: Decimal(100),
+            glucoseImpact: Decimal(0)
+        )
+        // delta = 25.5; Int(25.5)=25; 25/24=1 → result = 1.0
+        #expect(result == Decimal(1.0))
+    }
+
+    /// Rounding to one decimal place works when glucoseImpact has two decimals.
+    @Test("rounding one decimal place") func roundingOneDecimal() {
+        let result = DeterminationGenerator.calculateExpectedDelta(
+            targetGlucose: Decimal(124),
+            eventualGlucose: Decimal(100),
+            glucoseImpact: Decimal(string: "1.27")!
+        )
+        // delta=24 → blocks=1; adjustment=1; 1.27+1=2.27 → rounded to 2.3
+        #expect(result == Decimal(string: "2.3")!)
+    }
+
+    /// Extreme high eventual glucose produces a large negative expected delta.
+    @Test("extreme high eventual glucose") func extremeHighEventual() {
+        let result = DeterminationGenerator.calculateExpectedDelta(
+            targetGlucose: Decimal(120),
+            eventualGlucose: Decimal(350),
+            glucoseImpact: Decimal(0)
+        )
+        // delta = 120 - 350 = -230; Int(-230)/24 = -9 → result = 0 + (-9) = -9.0
+        #expect(result == Decimal(string: "-9.0")!)
+    }
+
+    /// Extreme low eventual glucose produces a positive expected delta.
+    @Test("extreme low eventual glucose") func extremeLowEventual() {
+        let result = DeterminationGenerator.calculateExpectedDelta(
+            targetGlucose: Decimal(120),
+            eventualGlucose: Decimal(39),
+            glucoseImpact: Decimal(0)
+        )
+        // delta = 81; Int(81)/24 = 3 → result = 0 + 3 = 3.0
+        #expect(result == Decimal(string: "3.0")!)
+    }
+
+    /// Invalid low‐unit input (<39 mg/dL) falls back to only using glucoseImpact.
+    @Test("invalid low input treated as only impact") func invalidLowInput() {
+        let result = DeterminationGenerator.calculateExpectedDelta(
+            targetGlucose: Decimal(5), // e.g. mmol/L mistakenly passed
+            eventualGlucose: Decimal(3),
+            glucoseImpact: Decimal(string: "1.7")!
+        )
+        // delta = 2; Int(2)/24 = 0 → result = 1.7 + 0 = 1.7
+        #expect(result == Decimal(string: "1.7")!)
+    }
+}

TrioTests/OpenAPSSwiftTests/SMBEnablementTests.swift → TrioTests/OpenAPSSwiftTests/DetermineBasalSMBEnablementTests.swift