DetermineBasalEventualOrForecastGlucoseLessThanMaxTests.swift 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import Foundation
  2. import Testing
  3. @testable import Trio
  4. /// These tests should be an exact copy of the JS tests here:
  5. /// - https://github.com/kingst/trio-oref/blob/dev-fixes-for-swift-comparison/tests/determine-basal-eventual-or-forecast-glucose-less-than-max.test.js
  6. @Suite("DosingEngine.eventualOrForecastGlucoseLessThanMax") struct DetermineBasalEventualOrForecastGlucoseLessThanMaxTests {
  7. private func defaultProfile() -> Profile {
  8. var profile = Profile()
  9. profile.maxBg = 120
  10. profile.currentBasal = 1.0
  11. profile.maxDailyBasal = 3.5
  12. profile.maxBasal = 1.5
  13. profile.outUnits = .mgdL
  14. return profile
  15. }
  16. private func callEventualOrForecastGlucoseLessThanMax(
  17. eventualGlucose: Decimal = 110,
  18. maxGlucose: Decimal? = nil,
  19. minPredictedGlucose: Decimal = 115,
  20. currentTemp: TempBasal = TempBasal(duration: 0, rate: 0, temp: .absolute, timestamp: Date()),
  21. basal: Decimal? = nil,
  22. smbIsEnabled: Bool = false,
  23. profile: Profile? = nil,
  24. determination: Determination? = nil
  25. ) throws -> (shouldSetTempBasal: Bool, determination: Determination) {
  26. let testProfile = profile ?? defaultProfile()
  27. let testDetermination = determination ?? Determination(
  28. id: nil,
  29. reason: "",
  30. units: nil,
  31. insulinReq: nil,
  32. eventualBG: nil,
  33. sensitivityRatio: nil,
  34. rate: nil,
  35. duration: nil,
  36. iob: nil,
  37. cob: nil,
  38. predictions: nil,
  39. deliverAt: nil,
  40. carbsReq: nil,
  41. temp: nil,
  42. bg: nil,
  43. reservoir: nil,
  44. isf: nil,
  45. timestamp: nil,
  46. tdd: nil,
  47. current_target: nil,
  48. minDelta: nil,
  49. expectedDelta: nil,
  50. minGuardBG: nil,
  51. minPredBG: nil,
  52. threshold: nil,
  53. carbRatio: nil,
  54. received: nil
  55. )
  56. return try DosingEngine.eventualOrForecastGlucoseLessThanMax(
  57. eventualGlucose: eventualGlucose,
  58. maxGlucose: maxGlucose ?? testProfile.maxBg!,
  59. minForecastGlucose: minPredictedGlucose,
  60. currentTemp: currentTemp,
  61. basal: basal ?? testProfile.currentBasal!,
  62. smbIsEnabled: smbIsEnabled,
  63. profile: testProfile,
  64. determination: testDetermination
  65. )
  66. }
  67. @Test("Guard: not less than max glucose") func testNotLessThanMaxGlucose() throws {
  68. let (shouldSet, determination) = try callEventualOrForecastGlucoseLessThanMax(
  69. eventualGlucose: 120,
  70. maxGlucose: 120,
  71. minPredictedGlucose: 125
  72. )
  73. #expect(shouldSet == false)
  74. #expect(determination.reason == "")
  75. }
  76. @Test("Guard: SMB is enabled") func testSmbIsEnabled() throws {
  77. let (shouldSet, determination) = try callEventualOrForecastGlucoseLessThanMax(smbIsEnabled: true)
  78. #expect(shouldSet == false)
  79. #expect(determination.reason == "")
  80. }
  81. @Test("Continue current temp") func testContinueCurrentTemp() throws {
  82. let profile = defaultProfile()
  83. let currentTemp = TempBasal(duration: 20, rate: profile.currentBasal!, temp: .absolute, timestamp: Date())
  84. let (shouldSet, determination) = try callEventualOrForecastGlucoseLessThanMax(
  85. currentTemp: currentTemp,
  86. basal: profile.currentBasal!,
  87. profile: profile
  88. )
  89. #expect(shouldSet == true)
  90. #expect(determination.rate == nil) // No change
  91. #expect(determination.reason.contains("temp \(currentTemp.rate) ~ req \(profile.currentBasal!)U/hr."))
  92. }
  93. @Test("Set new temp") func testSetNewTemp() throws {
  94. let profile = defaultProfile()
  95. let currentTemp = TempBasal(duration: 10, rate: 1.0, temp: .absolute, timestamp: Date())
  96. let basal: Decimal = 1.2
  97. let (shouldSet, determination) = try callEventualOrForecastGlucoseLessThanMax(
  98. currentTemp: currentTemp,
  99. basal: basal,
  100. profile: profile
  101. )
  102. #expect(shouldSet == true)
  103. #expect(determination.rate == basal)
  104. #expect(determination.duration == 30)
  105. #expect(determination.reason.contains("setting current basal of \(basal) as temp."))
  106. }
  107. @Test("Set new temp when rates differ") func testSetNewTempWhenRatesDiffer() throws {
  108. let profile = defaultProfile()
  109. // duration > 15, but rate is different from basal
  110. let currentTemp = TempBasal(duration: 20, rate: 1.0, temp: .absolute, timestamp: Date())
  111. let basal: Decimal = 1.2
  112. let (shouldSet, determination) = try callEventualOrForecastGlucoseLessThanMax(
  113. currentTemp: currentTemp,
  114. basal: basal,
  115. profile: profile
  116. )
  117. #expect(shouldSet == true)
  118. #expect(determination.rate == basal)
  119. #expect(determination.duration == 30)
  120. #expect(determination.reason.contains("setting current basal of \(basal) as temp."))
  121. }
  122. }