ProfileJavascriptTests.swift 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. import Foundation
  2. @testable import FreeAPS
  3. import Testing
  4. struct ProfileGeneratorTests {
  5. // Base test inputs that match the JavaScript test setup
  6. private func createBaseInputs() -> (
  7. PumpSettings,
  8. BGTargets,
  9. [BasalProfileEntry],
  10. InsulinSensitivities,
  11. Preferences,
  12. CarbRatios,
  13. [TempTarget],
  14. String,
  15. Autotune?,
  16. FreeAPSSettings
  17. ) {
  18. let pumpSettings = PumpSettings(
  19. insulinActionCurve: 3,
  20. maxBolus: 10,
  21. maxBasal: 2
  22. )
  23. let bgTargets = BGTargets(
  24. units: .mgdL,
  25. userPreferredUnits: .mgdL,
  26. targets: [
  27. BGTargetEntry(low: 100, high: 120, start: "00:00", offset: 0)
  28. ]
  29. )
  30. let basalProfile = [
  31. BasalProfileEntry(start: "00:00", minutes: 0, rate: 1.0)
  32. ]
  33. let isf = InsulinSensitivities(
  34. units: .mgdL,
  35. userPreferredUnits: .mgdL,
  36. sensitivities: [
  37. InsulinSensitivityEntry(sensitivity: 100, offset: 0, start: "00:00")
  38. ]
  39. )
  40. let preferences = Preferences()
  41. let carbRatios = CarbRatios(
  42. units: .grams,
  43. schedule: [
  44. CarbRatioEntry(start: "00:00", offset: 0, ratio: 20)
  45. ]
  46. )
  47. let tempTargets: [TempTarget] = []
  48. let model = "523"
  49. let autotune: Autotune? = nil
  50. let freeaps = FreeAPSSettings()
  51. return (pumpSettings, bgTargets, basalProfile, isf, preferences, carbRatios, tempTargets, model, autotune, freeaps)
  52. }
  53. @Test("Basic profile generation should create profile with correct values") func testBasicProfileGeneration() throws {
  54. let inputs = createBaseInputs()
  55. let profile = try ProfileGenerator.generate(
  56. pumpSettings: inputs.0,
  57. bgTargets: inputs.1,
  58. basalProfile: inputs.2,
  59. isf: inputs.3,
  60. preferences: inputs.4,
  61. carbRatios: inputs.5,
  62. tempTargets: inputs.6,
  63. model: inputs.7,
  64. autotune: inputs.8,
  65. freeaps: inputs.9
  66. )
  67. #expect(profile.maxIob == 0)
  68. #expect(profile.dia == 3)
  69. #expect(profile.sens == 100)
  70. #expect(profile.currentBasal == 1)
  71. #expect(profile.maxBg == 100)
  72. #expect(profile.minBg == 100)
  73. #expect(profile.carbRatio == 20)
  74. }
  75. @Test("Profile with active temp target should use temp target values") func testProfileWithTempTarget() throws {
  76. var inputs = createBaseInputs()
  77. // Create temp target 5 minutes ago that lasts 20 minutes
  78. let currentTime = Date()
  79. let creationDate = currentTime.addingTimeInterval(-5 * 60)
  80. let tempTarget = TempTarget(
  81. name: "Eating Soon",
  82. createdAt: creationDate,
  83. targetTop: 80,
  84. targetBottom: 80,
  85. duration: 20,
  86. enteredBy: "Test",
  87. reason: "Eating Soon",
  88. isPreset: nil,
  89. enabled: nil,
  90. halfBasalTarget: nil
  91. )
  92. inputs.6 = [tempTarget]
  93. let profile = try ProfileGenerator.generate(
  94. pumpSettings: inputs.0,
  95. bgTargets: inputs.1,
  96. basalProfile: inputs.2,
  97. isf: inputs.3,
  98. preferences: inputs.4,
  99. carbRatios: inputs.5,
  100. tempTargets: inputs.6,
  101. model: inputs.7,
  102. autotune: inputs.8,
  103. freeaps: inputs.9
  104. )
  105. #expect(profile.maxIob == 0)
  106. #expect(profile.dia == 3)
  107. #expect(profile.sens == 100)
  108. #expect(profile.currentBasal == 1)
  109. #expect(profile.maxBg == 80)
  110. #expect(profile.minBg == 80)
  111. #expect(profile.carbRatio == 20)
  112. #expect(profile.temptargetSet == true)
  113. }
  114. @Test("Profile with expired temp target should use default values") func testProfileWithExpiredTempTarget() throws {
  115. var inputs = createBaseInputs()
  116. // Create temp target 90 minutes ago
  117. let currentTime = Date()
  118. let creationDate = currentTime.addingTimeInterval(-90 * 60)
  119. let tempTarget = TempTarget(
  120. name: "Eating Soon",
  121. createdAt: creationDate,
  122. targetTop: 80,
  123. targetBottom: 80,
  124. duration: 20,
  125. enteredBy: "Test",
  126. reason: "Eating Soon",
  127. isPreset: nil,
  128. enabled: nil,
  129. halfBasalTarget: nil
  130. )
  131. inputs.6 = [tempTarget]
  132. let profile = try ProfileGenerator.generate(
  133. pumpSettings: inputs.0,
  134. bgTargets: inputs.1,
  135. basalProfile: inputs.2,
  136. isf: inputs.3,
  137. preferences: inputs.4,
  138. carbRatios: inputs.5,
  139. tempTargets: inputs.6,
  140. model: inputs.7,
  141. autotune: inputs.8,
  142. freeaps: inputs.9
  143. )
  144. #expect(profile.maxIob == 0)
  145. #expect(profile.dia == 3)
  146. #expect(profile.sens == 100)
  147. #expect(profile.currentBasal == 1)
  148. #expect(profile.maxBg == 100)
  149. #expect(profile.minBg == 100)
  150. #expect(profile.carbRatio == 20)
  151. }
  152. @Test("Profile with zero duration temp target should use default values") func testProfileWithZeroDurationTempTarget() throws {
  153. var inputs = createBaseInputs()
  154. // Create temp target 5 minutes ago with 0 duration
  155. let currentTime = Date()
  156. let creationDate = currentTime.addingTimeInterval(-5 * 60)
  157. let tempTarget = TempTarget(
  158. name: "Eating Soon",
  159. createdAt: creationDate,
  160. targetTop: 80,
  161. targetBottom: 80,
  162. duration: 0,
  163. enteredBy: "Test",
  164. reason: "Eating Soon",
  165. isPreset: nil,
  166. enabled: nil,
  167. halfBasalTarget: nil
  168. )
  169. inputs.6 = [tempTarget]
  170. let profile = try ProfileGenerator.generate(
  171. pumpSettings: inputs.0,
  172. bgTargets: inputs.1,
  173. basalProfile: inputs.2,
  174. isf: inputs.3,
  175. preferences: inputs.4,
  176. carbRatios: inputs.5,
  177. tempTargets: inputs.6,
  178. model: inputs.7,
  179. autotune: inputs.8,
  180. freeaps: inputs.9
  181. )
  182. #expect(profile.maxIob == 0)
  183. #expect(profile.dia == 3)
  184. #expect(profile.sens == 100)
  185. #expect(profile.currentBasal == 1)
  186. #expect(profile.maxBg == 100)
  187. #expect(profile.minBg == 100)
  188. #expect(profile.carbRatio == 20)
  189. }
  190. @Test("Profile generation with invalid DIA should throw error") func testInvalidDIA() throws {
  191. var inputs = createBaseInputs()
  192. inputs.0 = PumpSettings(
  193. insulinActionCurve: 1,
  194. maxBolus: 10,
  195. maxBasal: 2
  196. )
  197. #expect(throws: ProfileError.invalidDIA(value: 1)) {
  198. _ = try ProfileGenerator.generate(
  199. pumpSettings: inputs.0,
  200. bgTargets: inputs.1,
  201. basalProfile: inputs.2,
  202. isf: inputs.3,
  203. preferences: inputs.4,
  204. carbRatios: inputs.5,
  205. tempTargets: inputs.6,
  206. model: inputs.7,
  207. autotune: inputs.8,
  208. freeaps: inputs.9
  209. )
  210. }
  211. }
  212. @Test("Profile generation with zero basal rate should throw error") func testCurrentBasalZero() throws {
  213. var inputs = createBaseInputs()
  214. inputs.2 = [
  215. BasalProfileEntry(start: "00:00", minutes: 0, rate: 0.0)
  216. ]
  217. #expect(throws: ProfileError.invalidCurrentBasal(value: nil)) {
  218. _ = try ProfileGenerator.generate(
  219. pumpSettings: inputs.0,
  220. bgTargets: inputs.1,
  221. basalProfile: inputs.2,
  222. isf: inputs.3,
  223. preferences: inputs.4,
  224. carbRatios: inputs.5,
  225. tempTargets: inputs.6,
  226. model: inputs.7,
  227. autotune: inputs.8,
  228. freeaps: inputs.9
  229. )
  230. }
  231. }
  232. @Test("Profile should store model string correctly") func testModelString() throws {
  233. var inputs = createBaseInputs()
  234. inputs.7 = "\"554\"\n"
  235. let profile = try ProfileGenerator.generate(
  236. pumpSettings: inputs.0,
  237. bgTargets: inputs.1,
  238. basalProfile: inputs.2,
  239. isf: inputs.3,
  240. preferences: inputs.4,
  241. carbRatios: inputs.5,
  242. tempTargets: inputs.6,
  243. model: inputs.7,
  244. autotune: inputs.8,
  245. freeaps: inputs.9
  246. )
  247. #expect(profile.model == "554")
  248. }
  249. }