| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- import Foundation
- import Testing
- @testable import Trio
- /// The corresponding Javascript tests to confirm these numbers are here:
- /// - https://github.com/kingst/trio-oref/blob/dev-fixes-for-swift-comparison/tests/dynamic-isf.test.js
- @Suite("DynamicISF Calculation Tests") struct DynamicISFTests {
- // Helper to create common dependencies for tests
- private func createDependencies(
- useNewFormula: Bool = true,
- tdd: Decimal = 30,
- avgTDD: Decimal = 30,
- sensitivity: Decimal = 50,
- minAutosens: Decimal = 0.7,
- maxAutosens: Decimal = 1.2,
- useCustomPeakTime: Bool = false,
- insulinCurve: InsulinCurve = .rapidActing
- ) -> (Profile, Preferences, Decimal, TrioCustomOrefVariables) {
- var preferences = Preferences()
- preferences.useNewFormula = useNewFormula
- preferences.sigmoid = false
- preferences.adjustmentFactor = 0.8
- preferences.adjustmentFactorSigmoid = 0.5
- preferences.useCustomPeakTime = useCustomPeakTime
- preferences.curve = insulinCurve
- var profile = Profile()
- profile.sens = sensitivity
- profile.autosensMin = minAutosens
- profile.autosensMax = maxAutosens
- profile.minBg = 100
- profile.curve = insulinCurve
- profile.useCustomPeakTime = useCustomPeakTime
- profile.insulinPeakTime = 60 // For custom peak time test
- let glucose = Decimal(120)
- let trioVars = TrioCustomOrefVariables(
- average_total_data: avgTDD,
- weightedAverage: tdd,
- currentTDD: tdd,
- past2hoursAverage: 0,
- date: Date(),
- overridePercentage: 100,
- useOverride: false,
- duration: 0,
- unlimited: true,
- overrideTarget: 0,
- smbIsOff: false,
- advancedSettings: false,
- isfAndCr: false,
- isf: true,
- cr: true,
- smbIsScheduledOff: false,
- start: 0,
- end: 0,
- smbMinutes: 30,
- uamMinutes: 30
- )
- return (profile, preferences, glucose, trioVars)
- }
- @Test("Returns nil if dISF is disabled") func disabledReturnsNil() throws {
- let (profile, preferences, glucose, trioVars) = createDependencies(useNewFormula: false)
- let result = DynamicISF.calculate(
- profile: profile,
- preferences: preferences,
- currentGlucose: glucose,
- trioCustomOrefVariables: trioVars
- )
- #expect(result == nil)
- }
- @Test("Returns nil for invalid autosens limits") func invalidLimitsReturnsNil() throws {
- let (profile, preferences, glucose, trioVars) = createDependencies(minAutosens: 1.2, maxAutosens: 1.2)
- let result = DynamicISF.calculate(
- profile: profile,
- preferences: preferences,
- currentGlucose: glucose,
- trioCustomOrefVariables: trioVars
- )
- #expect(result == nil)
- }
- @Test("Logarithmic formula calculates all result fields correctly") func logarithmicFormula() throws {
- let (profile, preferences, glucose, trioVars) = createDependencies()
- let result = DynamicISF.calculate(
- profile: profile,
- preferences: preferences,
- currentGlucose: glucose,
- trioCustomOrefVariables: trioVars
- )!
- #expect(result.insulinFactor == 55)
- #expect(result.tddRatio.rounded(toPlaces: 2) == 1)
- #expect(result.ratio.rounded(toPlaces: 2) == 0.77)
- }
- @Test("Sigmoid formula calculates all result fields correctly") func sigmoidFormula() throws {
- var (profile, preferences, glucose, trioVars) = createDependencies()
- preferences.sigmoid = true
- let result = DynamicISF.calculate(
- profile: profile,
- preferences: preferences,
- currentGlucose: glucose,
- trioCustomOrefVariables: trioVars
- )!
- #expect(result.insulinFactor == 55)
- #expect(result.tddRatio == 1.0)
- #expect(result.ratio.rounded(scale: 2) == Decimal(string: "1.06"))
- }
- @Test("Uses default TDD ratio when average TDD is zero") func defaultTddRatio() throws {
- let (profile, preferences, glucose, trioVars) = createDependencies(avgTDD: 0)
- let result = DynamicISF.calculate(
- profile: profile,
- preferences: preferences,
- currentGlucose: glucose,
- trioCustomOrefVariables: trioVars
- )!
- #expect(result.tddRatio == 1.0)
- #expect(result.ratio.rounded(toPlaces: 2) == 0.77)
- }
- @Test("Uses custom peak time when enabled") func customPeakTime() throws {
- let (profile, preferences, glucose, trioVars) = createDependencies(useCustomPeakTime: true)
- let result = DynamicISF.calculate(
- profile: profile,
- preferences: preferences,
- currentGlucose: glucose,
- trioCustomOrefVariables: trioVars
- )!
- // 120 - profile.insulinPeakTime (60) = 60
- #expect(result.insulinFactor == 60)
- }
- @Test("Uses ultra-rapid insulin factor correctly") func ultraRapidInsulin() throws {
- let (profile, preferences, glucose, trioVars) = createDependencies(insulinCurve: .ultraRapid)
- let result = DynamicISF.calculate(
- profile: profile,
- preferences: preferences,
- currentGlucose: glucose,
- trioCustomOrefVariables: trioVars
- )!
- #expect(result.ratio.rounded(scale: 2) == Decimal(string: "0.7"))
- }
- @Test("Sigmoid handles maxLimit of 1 correctly") func sigmoidMaxLimitOne() throws {
- var (profile, preferences, glucose, trioVars) = createDependencies(maxAutosens: 1.0)
- preferences.sigmoid = true
- let result = DynamicISF.calculate(
- profile: profile,
- preferences: preferences,
- currentGlucose: glucose,
- trioCustomOrefVariables: trioVars
- )!
- #expect(result.insulinFactor == 55)
- #expect(result.tddRatio == 1.0)
- // BUG: you would expect this to be 1 but because of the fudge factor the
- // JS code uses to avoid divide by 0 it 0.99
- #expect(result.ratio.rounded(scale: 2) == Decimal(string: "0.99"))
- }
- @Test("Override with sigmoid adjusts target and ratio correctly") func overrideWithSigmoid() throws {
- var (profile, preferences, glucose, trioVars) = createDependencies()
- preferences.sigmoid = true
- trioVars.useOverride = true
- trioVars.overrideTarget = 80
- trioVars.overridePercentage = 80
- let result = DynamicISF.calculate(
- profile: profile,
- preferences: preferences,
- currentGlucose: glucose,
- trioCustomOrefVariables: trioVars
- )!
- #expect(result.ratio.rounded(toPlaces: 2) == Decimal(string: "1.11"))
- }
- }
|