|
|
@@ -0,0 +1,442 @@
|
|
|
+import Foundation
|
|
|
+import Testing
|
|
|
+@testable import Trio
|
|
|
+
|
|
|
+@Suite("DosingEngine: shouldEnableSmb Tests") struct DetermineBasalEnableSmbTests {
|
|
|
+ /// Helper to create a default set of inputs.
|
|
|
+ /// Each test can then modify the specific properties relevant to its case.
|
|
|
+ private func createDefaultInputs() -> (
|
|
|
+ profile: Profile,
|
|
|
+ meal: ComputedCarbs,
|
|
|
+ currentGlucose: Decimal,
|
|
|
+ adjustedTargetGlucose: Decimal,
|
|
|
+ adjustedSensitivity: Decimal,
|
|
|
+ minGuardGlucose: Decimal,
|
|
|
+ eventualGlucose: Decimal,
|
|
|
+ threshold: Decimal,
|
|
|
+ glucoseStatus: GlucoseStatus,
|
|
|
+ trioCustomOrefVariables: TrioCustomOrefVariables,
|
|
|
+ clock: Date
|
|
|
+ ) {
|
|
|
+ var profile = Profile()
|
|
|
+ // Ensure default is false so we can test enabling conditions.
|
|
|
+ profile.enableSMBAlways = false
|
|
|
+ profile.temptargetSet = false
|
|
|
+
|
|
|
+ let meal = ComputedCarbs(
|
|
|
+ carbs: 0,
|
|
|
+ mealCOB: 0,
|
|
|
+ currentDeviation: 0,
|
|
|
+ maxDeviation: 0,
|
|
|
+ minDeviation: 0,
|
|
|
+ slopeFromMaxDeviation: 0,
|
|
|
+ slopeFromMinDeviation: 0,
|
|
|
+ allDeviations: [],
|
|
|
+ lastCarbTime: Date().timeIntervalSince1970
|
|
|
+ )
|
|
|
+
|
|
|
+ let glucoseStatus = GlucoseStatus(
|
|
|
+ delta: 0,
|
|
|
+ glucose: 120,
|
|
|
+ noise: 0,
|
|
|
+ shortAvgDelta: 0,
|
|
|
+ longAvgDelta: 0,
|
|
|
+ date: Date(),
|
|
|
+ lastCalIndex: nil,
|
|
|
+ device: "test"
|
|
|
+ )
|
|
|
+
|
|
|
+ let trioCustomOrefVariables = TrioCustomOrefVariables(
|
|
|
+ average_total_data: 0,
|
|
|
+ weightedAverage: 0,
|
|
|
+ currentTDD: 0,
|
|
|
+ past2hoursAverage: 0,
|
|
|
+ date: Date(),
|
|
|
+ overridePercentage: 100,
|
|
|
+ useOverride: false,
|
|
|
+ duration: 0,
|
|
|
+ unlimited: false,
|
|
|
+ overrideTarget: 0,
|
|
|
+ smbIsOff: false,
|
|
|
+ advancedSettings: false,
|
|
|
+ isfAndCr: false,
|
|
|
+ isf: false,
|
|
|
+ cr: false,
|
|
|
+ smbIsScheduledOff: false,
|
|
|
+ start: 0,
|
|
|
+ end: 0,
|
|
|
+ smbMinutes: 0,
|
|
|
+ uamMinutes: 0,
|
|
|
+ shouldProtectDueToHIGH: false
|
|
|
+ )
|
|
|
+
|
|
|
+ return (
|
|
|
+ profile: profile,
|
|
|
+ meal: meal,
|
|
|
+ currentGlucose: 120,
|
|
|
+ adjustedTargetGlucose: 100,
|
|
|
+ adjustedSensitivity: 50,
|
|
|
+ minGuardGlucose: 110,
|
|
|
+ eventualGlucose: 115,
|
|
|
+ threshold: 70,
|
|
|
+ glucoseStatus: glucoseStatus,
|
|
|
+ trioCustomOrefVariables: trioCustomOrefVariables,
|
|
|
+ clock: Date()
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
+ // MARK: - Disabling Conditions
|
|
|
+
|
|
|
+ @Test("Should return false by default with no enabling preferences") func defaultIsFalse() throws {
|
|
|
+ let inputs = createDefaultInputs()
|
|
|
+ let decision = try DosingEngine.makeSMBDosingDecision(
|
|
|
+ profile: inputs.profile, meal: inputs.meal, currentGlucose: inputs.currentGlucose,
|
|
|
+ adjustedTargetGlucose: inputs.adjustedTargetGlucose, adjustedSensitivity: inputs.adjustedSensitivity,
|
|
|
+ minGuardGlucose: inputs.minGuardGlucose, eventualGlucose: inputs.eventualGlucose,
|
|
|
+ threshold: inputs.threshold, glucoseStatus: inputs.glucoseStatus,
|
|
|
+ trioCustomOrefVariables: inputs.trioCustomOrefVariables, clock: inputs.clock
|
|
|
+ )
|
|
|
+ #expect(decision.isEnabled == false)
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test("Should disable SMB when smbIsOff is true") func disableWhenSmbIsOff() throws {
|
|
|
+ var inputs = createDefaultInputs()
|
|
|
+ inputs.trioCustomOrefVariables.smbIsOff = true
|
|
|
+ inputs.profile.enableSMBAlways = true // Ensure smbIsOff takes precedence
|
|
|
+
|
|
|
+ let decision = try DosingEngine.makeSMBDosingDecision(
|
|
|
+ profile: inputs.profile, meal: inputs.meal, currentGlucose: inputs.currentGlucose,
|
|
|
+ adjustedTargetGlucose: inputs.adjustedTargetGlucose, adjustedSensitivity: inputs.adjustedSensitivity,
|
|
|
+ minGuardGlucose: inputs.minGuardGlucose, eventualGlucose: inputs.eventualGlucose,
|
|
|
+ threshold: inputs.threshold, glucoseStatus: inputs.glucoseStatus,
|
|
|
+ trioCustomOrefVariables: inputs.trioCustomOrefVariables, clock: inputs.clock
|
|
|
+ )
|
|
|
+ #expect(decision.isEnabled == false)
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test("Should disable SMB when shouldProtectDueToHIGH is true") func disableWhenProtectDueToHigh() throws {
|
|
|
+ var inputs = createDefaultInputs()
|
|
|
+ inputs.trioCustomOrefVariables.shouldProtectDueToHIGH = true
|
|
|
+ inputs.profile.enableSMBAlways = true // Ensure protection takes precedence
|
|
|
+
|
|
|
+ let decision = try DosingEngine.makeSMBDosingDecision(
|
|
|
+ profile: inputs.profile, meal: inputs.meal, currentGlucose: inputs.currentGlucose,
|
|
|
+ adjustedTargetGlucose: inputs.adjustedTargetGlucose, adjustedSensitivity: inputs.adjustedSensitivity,
|
|
|
+ minGuardGlucose: inputs.minGuardGlucose, eventualGlucose: inputs.eventualGlucose,
|
|
|
+ threshold: inputs.threshold, glucoseStatus: inputs.glucoseStatus,
|
|
|
+ trioCustomOrefVariables: inputs.trioCustomOrefVariables, clock: inputs.clock
|
|
|
+ )
|
|
|
+ #expect(decision.isEnabled == false)
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test("Should disable SMB with high temp target when not allowed") func disableWithHighTempTarget() throws {
|
|
|
+ var inputs = createDefaultInputs()
|
|
|
+ inputs.profile.allowSMBWithHighTemptarget = false
|
|
|
+ inputs.profile.temptargetSet = true
|
|
|
+ inputs.adjustedTargetGlucose = 120
|
|
|
+
|
|
|
+ let decision = try DosingEngine.makeSMBDosingDecision(
|
|
|
+ profile: inputs.profile, meal: inputs.meal, currentGlucose: inputs.currentGlucose,
|
|
|
+ adjustedTargetGlucose: inputs.adjustedTargetGlucose, adjustedSensitivity: inputs.adjustedSensitivity,
|
|
|
+ minGuardGlucose: inputs.minGuardGlucose, eventualGlucose: inputs.eventualGlucose,
|
|
|
+ threshold: inputs.threshold, glucoseStatus: inputs.glucoseStatus,
|
|
|
+ trioCustomOrefVariables: inputs.trioCustomOrefVariables, clock: inputs.clock
|
|
|
+ )
|
|
|
+ #expect(decision.isEnabled == false)
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test("Should disable SMB when minGuardGlucose is below threshold") func disableWhenMinGuardBelowThreshold() throws {
|
|
|
+ var inputs = createDefaultInputs()
|
|
|
+ inputs.profile.enableSMBAlways = true // Enable SMB initially to test the safety override
|
|
|
+ inputs.minGuardGlucose = 65
|
|
|
+ inputs.threshold = 70
|
|
|
+
|
|
|
+ let decision = try DosingEngine.makeSMBDosingDecision(
|
|
|
+ profile: inputs.profile, meal: inputs.meal, currentGlucose: inputs.currentGlucose,
|
|
|
+ adjustedTargetGlucose: inputs.adjustedTargetGlucose, adjustedSensitivity: inputs.adjustedSensitivity,
|
|
|
+ minGuardGlucose: inputs.minGuardGlucose, eventualGlucose: inputs.eventualGlucose,
|
|
|
+ threshold: inputs.threshold, glucoseStatus: inputs.glucoseStatus,
|
|
|
+ trioCustomOrefVariables: inputs.trioCustomOrefVariables, clock: inputs.clock
|
|
|
+ )
|
|
|
+ #expect(decision.isEnabled == false)
|
|
|
+ #expect(decision.manualBolusError == 1)
|
|
|
+ #expect(decision.minGuardGlucose == 65)
|
|
|
+ #expect(decision.insulinForManualBolus != nil)
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test("Should disable SMB when maxDelta is too high") func disableWhenMaxDeltaTooHigh() throws {
|
|
|
+ var inputs = createDefaultInputs()
|
|
|
+ inputs.profile.enableSMBAlways = true // Enable SMB initially
|
|
|
+ inputs.profile.maxDeltaBgThreshold = 0.2
|
|
|
+ inputs.currentGlucose = 100
|
|
|
+ // Set maxDelta to be > 20% of currentGlucose
|
|
|
+ inputs.glucoseStatus = GlucoseStatus(
|
|
|
+ delta: 21,
|
|
|
+ glucose: 100,
|
|
|
+ noise: 0,
|
|
|
+ shortAvgDelta: 5,
|
|
|
+ longAvgDelta: 5,
|
|
|
+ date: Date(),
|
|
|
+ lastCalIndex: nil,
|
|
|
+ device: "test"
|
|
|
+ )
|
|
|
+
|
|
|
+ let decision = try DosingEngine.makeSMBDosingDecision(
|
|
|
+ profile: inputs.profile, meal: inputs.meal, currentGlucose: inputs.currentGlucose,
|
|
|
+ adjustedTargetGlucose: inputs.adjustedTargetGlucose, adjustedSensitivity: inputs.adjustedSensitivity,
|
|
|
+ minGuardGlucose: inputs.minGuardGlucose, eventualGlucose: inputs.eventualGlucose,
|
|
|
+ threshold: inputs.threshold, glucoseStatus: inputs.glucoseStatus,
|
|
|
+ trioCustomOrefVariables: inputs.trioCustomOrefVariables, clock: inputs.clock
|
|
|
+ )
|
|
|
+ #expect(decision.isEnabled == false)
|
|
|
+ #expect(decision.reason != nil)
|
|
|
+ }
|
|
|
+
|
|
|
+ // MARK: - Enabling Conditions
|
|
|
+
|
|
|
+ @Test("Should enable SMB when enableSMBAlways is true") func enableWhenAlwaysOn() throws {
|
|
|
+ var inputs = createDefaultInputs()
|
|
|
+ inputs.profile.enableSMBAlways = true
|
|
|
+
|
|
|
+ let decision = try DosingEngine.makeSMBDosingDecision(
|
|
|
+ profile: inputs.profile, meal: inputs.meal, currentGlucose: inputs.currentGlucose,
|
|
|
+ adjustedTargetGlucose: inputs.adjustedTargetGlucose, adjustedSensitivity: inputs.adjustedSensitivity,
|
|
|
+ minGuardGlucose: inputs.minGuardGlucose, eventualGlucose: inputs.eventualGlucose,
|
|
|
+ threshold: inputs.threshold, glucoseStatus: inputs.glucoseStatus,
|
|
|
+ trioCustomOrefVariables: inputs.trioCustomOrefVariables, clock: inputs.clock
|
|
|
+ )
|
|
|
+ #expect(decision.isEnabled == true)
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test("Should enable SMB with COB") func enableWithCob() throws {
|
|
|
+ var inputs = createDefaultInputs()
|
|
|
+ inputs.profile.enableSMBWithCOB = true
|
|
|
+ inputs.meal = ComputedCarbs(
|
|
|
+ carbs: 20,
|
|
|
+ mealCOB: 10,
|
|
|
+ currentDeviation: 0,
|
|
|
+ maxDeviation: 0,
|
|
|
+ minDeviation: 0,
|
|
|
+ slopeFromMaxDeviation: 0,
|
|
|
+ slopeFromMinDeviation: 0,
|
|
|
+ allDeviations: [],
|
|
|
+ lastCarbTime: Date().timeIntervalSince1970
|
|
|
+ )
|
|
|
+
|
|
|
+ let decision = try DosingEngine.makeSMBDosingDecision(
|
|
|
+ profile: inputs.profile, meal: inputs.meal, currentGlucose: inputs.currentGlucose,
|
|
|
+ adjustedTargetGlucose: inputs.adjustedTargetGlucose, adjustedSensitivity: inputs.adjustedSensitivity,
|
|
|
+ minGuardGlucose: inputs.minGuardGlucose, eventualGlucose: inputs.eventualGlucose,
|
|
|
+ threshold: inputs.threshold, glucoseStatus: inputs.glucoseStatus,
|
|
|
+ trioCustomOrefVariables: inputs.trioCustomOrefVariables, clock: inputs.clock
|
|
|
+ )
|
|
|
+ #expect(decision.isEnabled == true)
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test("Should enable SMB after carbs") func enableAfterCarbs() throws {
|
|
|
+ var inputs = createDefaultInputs()
|
|
|
+ inputs.profile.enableSMBAfterCarbs = true
|
|
|
+ inputs.meal = ComputedCarbs(
|
|
|
+ carbs: 20,
|
|
|
+ mealCOB: 0,
|
|
|
+ currentDeviation: 0,
|
|
|
+ maxDeviation: 0,
|
|
|
+ minDeviation: 0,
|
|
|
+ slopeFromMaxDeviation: 0,
|
|
|
+ slopeFromMinDeviation: 0,
|
|
|
+ allDeviations: [],
|
|
|
+ lastCarbTime: Date().timeIntervalSince1970
|
|
|
+ )
|
|
|
+
|
|
|
+ let decision = try DosingEngine.makeSMBDosingDecision(
|
|
|
+ profile: inputs.profile, meal: inputs.meal, currentGlucose: inputs.currentGlucose,
|
|
|
+ adjustedTargetGlucose: inputs.adjustedTargetGlucose, adjustedSensitivity: inputs.adjustedSensitivity,
|
|
|
+ minGuardGlucose: inputs.minGuardGlucose, eventualGlucose: inputs.eventualGlucose,
|
|
|
+ threshold: inputs.threshold, glucoseStatus: inputs.glucoseStatus,
|
|
|
+ trioCustomOrefVariables: inputs.trioCustomOrefVariables, clock: inputs.clock
|
|
|
+ )
|
|
|
+ #expect(decision.isEnabled == true)
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test("Should enable SMB with low temp target") func enableWithLowTempTarget() throws {
|
|
|
+ var inputs = createDefaultInputs()
|
|
|
+ inputs.profile.enableSMBWithTemptarget = true
|
|
|
+ inputs.profile.temptargetSet = true
|
|
|
+ inputs.adjustedTargetGlucose = 90
|
|
|
+
|
|
|
+ let decision = try DosingEngine.makeSMBDosingDecision(
|
|
|
+ profile: inputs.profile, meal: inputs.meal, currentGlucose: inputs.currentGlucose,
|
|
|
+ adjustedTargetGlucose: inputs.adjustedTargetGlucose, adjustedSensitivity: inputs.adjustedSensitivity,
|
|
|
+ minGuardGlucose: inputs.minGuardGlucose, eventualGlucose: inputs.eventualGlucose,
|
|
|
+ threshold: inputs.threshold, glucoseStatus: inputs.glucoseStatus,
|
|
|
+ trioCustomOrefVariables: inputs.trioCustomOrefVariables, clock: inputs.clock
|
|
|
+ )
|
|
|
+ #expect(decision.isEnabled == true)
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test("Should enable SMB for high BG") func enableWithHighBg() throws {
|
|
|
+ var inputs = createDefaultInputs()
|
|
|
+ inputs.profile.enableSMBHighBg = true
|
|
|
+ inputs.profile.enableSMBHighBgTarget = 140
|
|
|
+ inputs.currentGlucose = 145
|
|
|
+
|
|
|
+ let decision = try DosingEngine.makeSMBDosingDecision(
|
|
|
+ profile: inputs.profile, meal: inputs.meal, currentGlucose: inputs.currentGlucose,
|
|
|
+ adjustedTargetGlucose: inputs.adjustedTargetGlucose, adjustedSensitivity: inputs.adjustedSensitivity,
|
|
|
+ minGuardGlucose: inputs.minGuardGlucose, eventualGlucose: inputs.eventualGlucose,
|
|
|
+ threshold: inputs.threshold, glucoseStatus: inputs.glucoseStatus,
|
|
|
+ trioCustomOrefVariables: inputs.trioCustomOrefVariables, clock: inputs.clock
|
|
|
+ )
|
|
|
+ #expect(decision.isEnabled == true)
|
|
|
+ }
|
|
|
+
|
|
|
+ // MARK: - Scheduled Off Tests
|
|
|
+
|
|
|
+ @Test("Scheduled Off (Normal): should disable SMB inside the window") func scheduledOffNormal_Inside() throws {
|
|
|
+ var inputs = createDefaultInputs()
|
|
|
+ inputs.profile.enableSMBAlways = true // Ensure schedule is the only reason for failure
|
|
|
+ inputs.trioCustomOrefVariables.smbIsScheduledOff = true
|
|
|
+ inputs.trioCustomOrefVariables.start = 9 // 9 AM
|
|
|
+ inputs.trioCustomOrefVariables.end = 17 // 5 PM
|
|
|
+ inputs.clock = Calendar.current.date(bySettingHour: 14, minute: 0, second: 0, of: Date())!
|
|
|
+
|
|
|
+ let decision = try DosingEngine.makeSMBDosingDecision(
|
|
|
+ profile: inputs.profile, meal: inputs.meal, currentGlucose: inputs.currentGlucose,
|
|
|
+ adjustedTargetGlucose: inputs.adjustedTargetGlucose, adjustedSensitivity: inputs.adjustedSensitivity,
|
|
|
+ minGuardGlucose: inputs.minGuardGlucose, eventualGlucose: inputs.eventualGlucose,
|
|
|
+ threshold: inputs.threshold, glucoseStatus: inputs.glucoseStatus,
|
|
|
+ trioCustomOrefVariables: inputs.trioCustomOrefVariables, clock: inputs.clock
|
|
|
+ )
|
|
|
+ #expect(decision.isEnabled == false)
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test("Scheduled Off (Normal): should NOT disable SMB outside the window") func scheduledOffNormal_Outside() throws {
|
|
|
+ var inputs = createDefaultInputs()
|
|
|
+ inputs.profile.enableSMBAlways = true
|
|
|
+ inputs.trioCustomOrefVariables.smbIsScheduledOff = true
|
|
|
+ inputs.trioCustomOrefVariables.start = 9 // 9 AM
|
|
|
+ inputs.trioCustomOrefVariables.end = 17 // 5 PM
|
|
|
+ inputs.clock = Calendar.current.date(bySettingHour: 18, minute: 0, second: 0, of: Date())!
|
|
|
+
|
|
|
+ let decision = try DosingEngine.makeSMBDosingDecision(
|
|
|
+ profile: inputs.profile, meal: inputs.meal, currentGlucose: inputs.currentGlucose,
|
|
|
+ adjustedTargetGlucose: inputs.adjustedTargetGlucose, adjustedSensitivity: inputs.adjustedSensitivity,
|
|
|
+ minGuardGlucose: inputs.minGuardGlucose, eventualGlucose: inputs.eventualGlucose,
|
|
|
+ threshold: inputs.threshold, glucoseStatus: inputs.glucoseStatus,
|
|
|
+ trioCustomOrefVariables: inputs.trioCustomOrefVariables, clock: inputs.clock
|
|
|
+ )
|
|
|
+ #expect(decision.isEnabled == true)
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test(
|
|
|
+ "Scheduled Off (Wrapping): should disable SMB inside the window (after midnight)"
|
|
|
+ ) func scheduledOffWrapping_InsideAfterMidnight() throws {
|
|
|
+ var inputs = createDefaultInputs()
|
|
|
+ inputs.profile.enableSMBAlways = true
|
|
|
+ inputs.trioCustomOrefVariables.smbIsScheduledOff = true
|
|
|
+ inputs.trioCustomOrefVariables.start = 22 // 10 PM
|
|
|
+ inputs.trioCustomOrefVariables.end = 6 // 6 AM
|
|
|
+ inputs.clock = Calendar.current.date(bySettingHour: 2, minute: 0, second: 0, of: Date())!
|
|
|
+
|
|
|
+ let decision = try DosingEngine.makeSMBDosingDecision(
|
|
|
+ profile: inputs.profile, meal: inputs.meal, currentGlucose: inputs.currentGlucose,
|
|
|
+ adjustedTargetGlucose: inputs.adjustedTargetGlucose, adjustedSensitivity: inputs.adjustedSensitivity,
|
|
|
+ minGuardGlucose: inputs.minGuardGlucose, eventualGlucose: inputs.eventualGlucose,
|
|
|
+ threshold: inputs.threshold, glucoseStatus: inputs.glucoseStatus,
|
|
|
+ trioCustomOrefVariables: inputs.trioCustomOrefVariables, clock: inputs.clock
|
|
|
+ )
|
|
|
+ #expect(decision.isEnabled == false)
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test(
|
|
|
+ "Scheduled Off (Wrapping): should disable SMB inside the window (before midnight)"
|
|
|
+ ) func scheduledOffWrapping_InsideBeforeMidnight() throws {
|
|
|
+ var inputs = createDefaultInputs()
|
|
|
+ inputs.profile.enableSMBAlways = true
|
|
|
+ inputs.trioCustomOrefVariables.smbIsScheduledOff = true
|
|
|
+ inputs.trioCustomOrefVariables.start = 22 // 10 PM
|
|
|
+ inputs.trioCustomOrefVariables.end = 6 // 6 AM
|
|
|
+ inputs.clock = Calendar.current.date(bySettingHour: 23, minute: 0, second: 0, of: Date())!
|
|
|
+
|
|
|
+ let decision = try DosingEngine.makeSMBDosingDecision(
|
|
|
+ profile: inputs.profile, meal: inputs.meal, currentGlucose: inputs.currentGlucose,
|
|
|
+ adjustedTargetGlucose: inputs.adjustedTargetGlucose, adjustedSensitivity: inputs.adjustedSensitivity,
|
|
|
+ minGuardGlucose: inputs.minGuardGlucose, eventualGlucose: inputs.eventualGlucose,
|
|
|
+ threshold: inputs.threshold, glucoseStatus: inputs.glucoseStatus,
|
|
|
+ trioCustomOrefVariables: inputs.trioCustomOrefVariables, clock: inputs.clock
|
|
|
+ )
|
|
|
+ #expect(decision.isEnabled == false)
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test("Scheduled Off (Wrapping): should NOT disable SMB outside the window") func scheduledOffWrapping_Outside() throws {
|
|
|
+ var inputs = createDefaultInputs()
|
|
|
+ inputs.profile.enableSMBAlways = true
|
|
|
+ inputs.trioCustomOrefVariables.smbIsScheduledOff = true
|
|
|
+ inputs.trioCustomOrefVariables.start = 22 // 10 PM
|
|
|
+ inputs.trioCustomOrefVariables.end = 6 // 6 AM
|
|
|
+ inputs.clock = Calendar.current.date(bySettingHour: 12, minute: 0, second: 0, of: Date())!
|
|
|
+
|
|
|
+ let decision = try DosingEngine.makeSMBDosingDecision(
|
|
|
+ profile: inputs.profile, meal: inputs.meal, currentGlucose: inputs.currentGlucose,
|
|
|
+ adjustedTargetGlucose: inputs.adjustedTargetGlucose, adjustedSensitivity: inputs.adjustedSensitivity,
|
|
|
+ minGuardGlucose: inputs.minGuardGlucose, eventualGlucose: inputs.eventualGlucose,
|
|
|
+ threshold: inputs.threshold, glucoseStatus: inputs.glucoseStatus,
|
|
|
+ trioCustomOrefVariables: inputs.trioCustomOrefVariables, clock: inputs.clock
|
|
|
+ )
|
|
|
+ #expect(decision.isEnabled == true)
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test("Scheduled Off (All Day): should disable SMB") func scheduledOffAllDay() throws {
|
|
|
+ var inputs = createDefaultInputs()
|
|
|
+ inputs.profile.enableSMBAlways = true
|
|
|
+ inputs.trioCustomOrefVariables.smbIsScheduledOff = true
|
|
|
+ inputs.trioCustomOrefVariables.start = 0
|
|
|
+ inputs.trioCustomOrefVariables.end = 0
|
|
|
+ inputs.clock = Calendar.current.date(bySettingHour: 15, minute: 0, second: 0, of: Date())!
|
|
|
+
|
|
|
+ let decision = try DosingEngine.makeSMBDosingDecision(
|
|
|
+ profile: inputs.profile, meal: inputs.meal, currentGlucose: inputs.currentGlucose,
|
|
|
+ adjustedTargetGlucose: inputs.adjustedTargetGlucose, adjustedSensitivity: inputs.adjustedSensitivity,
|
|
|
+ minGuardGlucose: inputs.minGuardGlucose, eventualGlucose: inputs.eventualGlucose,
|
|
|
+ threshold: inputs.threshold, glucoseStatus: inputs.glucoseStatus,
|
|
|
+ trioCustomOrefVariables: inputs.trioCustomOrefVariables, clock: inputs.clock
|
|
|
+ )
|
|
|
+ #expect(decision.isEnabled == false)
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test("Scheduled Off (Single Hour): should disable SMB inside the window") func scheduledOffSingleHour_Inside() throws {
|
|
|
+ var inputs = createDefaultInputs()
|
|
|
+ inputs.profile.enableSMBAlways = true
|
|
|
+ inputs.trioCustomOrefVariables.smbIsScheduledOff = true
|
|
|
+ inputs.trioCustomOrefVariables.start = 11 // 11 AM
|
|
|
+ inputs.trioCustomOrefVariables.end = 11 // 11 AM
|
|
|
+ inputs.clock = Calendar.current.date(bySettingHour: 11, minute: 30, second: 0, of: Date())!
|
|
|
+
|
|
|
+ let decision = try DosingEngine.makeSMBDosingDecision(
|
|
|
+ profile: inputs.profile, meal: inputs.meal, currentGlucose: inputs.currentGlucose,
|
|
|
+ adjustedTargetGlucose: inputs.adjustedTargetGlucose, adjustedSensitivity: inputs.adjustedSensitivity,
|
|
|
+ minGuardGlucose: inputs.minGuardGlucose, eventualGlucose: inputs.eventualGlucose,
|
|
|
+ threshold: inputs.threshold, glucoseStatus: inputs.glucoseStatus,
|
|
|
+ trioCustomOrefVariables: inputs.trioCustomOrefVariables, clock: inputs.clock
|
|
|
+ )
|
|
|
+ #expect(decision.isEnabled == false)
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test("Scheduled Off (Single Hour): should NOT disable SMB outside the window") func scheduledOffSingleHour_Outside() throws {
|
|
|
+ var inputs = createDefaultInputs()
|
|
|
+ inputs.profile.enableSMBAlways = true
|
|
|
+ inputs.trioCustomOrefVariables.smbIsScheduledOff = true
|
|
|
+ inputs.trioCustomOrefVariables.start = 11 // 11 AM
|
|
|
+ inputs.trioCustomOrefVariables.end = 11 // 11 AM
|
|
|
+ inputs.clock = Calendar.current.date(bySettingHour: 12, minute: 0, second: 0, of: Date())!
|
|
|
+
|
|
|
+ let decision = try DosingEngine.makeSMBDosingDecision(
|
|
|
+ profile: inputs.profile, meal: inputs.meal, currentGlucose: inputs.currentGlucose,
|
|
|
+ adjustedTargetGlucose: inputs.adjustedTargetGlucose, adjustedSensitivity: inputs.adjustedSensitivity,
|
|
|
+ minGuardGlucose: inputs.minGuardGlucose, eventualGlucose: inputs.eventualGlucose,
|
|
|
+ threshold: inputs.threshold, glucoseStatus: inputs.glucoseStatus,
|
|
|
+ trioCustomOrefVariables: inputs.trioCustomOrefVariables, clock: inputs.clock
|
|
|
+ )
|
|
|
+ #expect(decision.isEnabled == true)
|
|
|
+ }
|
|
|
+}
|